跳到主要内容

编码题

水平垂直居中

垂直居中的方案

1、

line-height: 200px;
vertical-align: middle;

2、CSS Table

#parent {display: table;}
#child {
display: table-cell;
vertical-align: middle;
}

3、Absolute Positioning and Negative Margin

#parent {position: relative;}
#child {
position: absolute;
top: 50%;
left: 50%;
height: 30%;
width: 50%;
margin: -15% 0 0 -25%;
}

4、Absolute Positioning and Stretching

#parent {position: relative;}
#child {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 50%;
height: 30%;
margin: auto;
}

5、Equal Top and Bottom Padding

#parent {
padding: 5% 0;
}
#child {
padding: 10% 0;
}

答案参见 css 居中文档

可以参考下表进行记忆

居中方式内联元素块元素
水平居中text-align 设置为 centermargin
1
垂直居中当行采用 line-heightsdf

水平垂直居中定位

直居中的方案

1、

line-height: 200px;
vertical-align: middle;

2、CSS Table

#parent {display: table;}
#child {
display: table-cell;
vertical-align: middle;
}

3、Absolute Positioning and Negative Margin

#parent {position: relative;}
#child {
position: absolute;
top: 50%;
left: 50%;
height: 30%;
width: 50%;
margin: -15% 0 0 -25%;
}

4、Absolute Positioning and Stretching

#parent {position: relative;}
#child {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 50%;
height: 30%;
margin: auto;
}

5、Equal Top and Bottom Padding

#parent {
padding: 5% 0;
}
#child {
padding: 10% 0;
}

平居中的方案

1、要实现行内元素<span>、<a>等的水平居中:text-align:center;

2、要实现块状元素(display:block)的水平居中: margin:0 auto;

3、多个水平排列的块状元素的水平居中:

#container{
text-align:center;
}
#center{
display:inline-block;
}

4、flexbox

#container {
display: flex;
}
#container {
display: inline-flex;
}

5、一直宽度水平居中:绝对定位与负边距实现。

#container{
position:relative;
}

#center{
width:100px;
height:100px;
position:absolute;
top:50%;
left:50%;
margin:-50px 0 0 -50px;
}

6、绝对定位与margin:

#container{
position:relative;
}
#center{
position:absolute;
margin:auto;
top:0;
bottom:0;
left:0;
right:0;
}

知高度和宽度元素的水平垂直居中

1、当要被居中的元素是inline或者inline-block元素

 #container{
display:table-cell;
text-align:center;
vertical-align:middle;
}

#center{

}

2、利用Css3的transform,可以轻松的在未知元素的高宽的情况下实现元素的垂直居中。

#container{
position:relative;
}
#center{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}

3、flex

#container{
display:flex;
justify-content:center;
align-items: center;
}

#center{

}

如何实现页面文本不可选中,不可复制

答案

核心概念

可以通过 CSS 和 JavaScript 结合的方式实现页面文本不可选中和不可复制。这种技术常用于保护版权内容或防止用户复制敏感信息。

CSS 实现方法

可以通过设置 CSS 属性来禁止用户选中页面文本:

body {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}

这将禁止在整个页面上进行文本选择。

JavaScript 增强实现

如果仅使用 CSS 不能满足需求,可以结合 JavaScript 进一步增强禁止复制的功能:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
</head>
<body>
<p>这是一些不可选中和不可复制的文本。</p>
<script>
document.addEventListener("copy", function (e) {
e.preventDefault();
});
</script>
</body>
</html>

在这个例子中,通过监听 copy 事件并调用 preventDefault() 方法来阻止复制操作。

示例说明

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文本不可选中和不可复制演示</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
            background-color: #f5f5f5;
        }
        
        .container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        
        .demo-section {
            margin: 20px 0;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 5px;
        }
        
        .normal-text {
            background: #e8f5e8;
            padding: 15px;
            border-radius: 5px;
            margin: 10px 0;
        }
        
        .unselectable-text {
            background: #ffe8e8;
            padding: 15px;
            border-radius: 5px;
            margin: 10px 0;
            -webkit-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none;
        }
        
        .protected-text {
            background: #fff3cd;
            padding: 15px;
            border-radius: 5px;
            margin: 10px 0;
            -webkit-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none;
        }
        
        .controls {
            margin: 20px 0;
            padding: 15px;
            background: #e8f4fd;
            border-radius: 5px;
        }
        
        button {
            margin: 5px;
            padding: 8px 16px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        
        button:hover {
            background-color: #45a049;
        }
        
        .warning {
            background: #fff3cd;
            border-left: 4px solid #ffc107;
            padding: 15px;
            margin: 20px 0;
            border-radius: 4px;
        }
        
        h2 {
            color: #333;
            border-bottom: 2px solid #4CAF50;
            padding-bottom: 5px;
        }
        
        .test-area {
            background: #f8f9fa;
            padding: 15px;
            border-radius: 5px;
            margin: 20px 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>文本不可选中和不可复制演示</h1>
        
        <div class="warning">
            <h3>⚠️ 注意事项</h3>
            <ul>
                <li>这种方法不能阻止用户通过开发者工具查看源代码</li>
                <li>建议谨慎使用,避免影响用户体验</li>
                <li>主要用于保护版权内容或敏感信息</li>
            </ul>
        </div>
        
        <div class="demo-section">
            <h2>1. 正常文本(可选中和复制)</h2>
            <div class="normal-text">
                这是一段正常的文本,你可以选中和复制这段文字。这段文字包含了重要的信息,用户应该能够自由地选择和复制。
            </div>
            <p><strong>测试:</strong>尝试选中和复制上面的文字</p>
        </div>
        
        <div class="demo-section">
            <h2>2. 仅 CSS 禁用选择</h2>
            <div class="unselectable-text">
                这是一段不可选中的文本,通过 CSS 的 user-select: none 实现。你可以尝试选中这段文字,但会发现无法选中。
            </div>
            <p><strong>测试:</strong>尝试选中上面的文字(应该无法选中)</p>
        </div>
        
        <div class="demo-section">
            <h2>3. CSS + JavaScript 完全保护</h2>
            <div class="protected-text" id="protected-text">
                这是一段完全保护的文本,既不能选中也不能复制。通过 CSS 禁用选择,JavaScript 阻止复制操作。
            </div>
            <p><strong>测试:</strong>尝试选中和复制上面的文字</p>
        </div>
        
        <div class="controls">
            <h3>控制面板</h3>
            <button onclick="toggleProtection()">切换保护状态</button>
            <button onclick="testCopy()">测试复制功能</button>
            <button onclick="resetAll()">重置所有</button>
        </div>
        
        <div class="test-area">
            <h3>测试区域</h3>
            <p>在下面的文本框中测试复制功能:</p>
            <textarea id="test-textarea" rows="4" cols="50" placeholder="在这里粘贴测试复制的内容..."></textarea>
        </div>
        
        <div class="demo-section">
            <h2>实现代码</h2>
            <pre><code>/* CSS 禁用选择 */
.unselectable-text {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

/* JavaScript 阻止复制 */
document.addEventListener("copy", function (e) {
  e.preventDefault();
});</code></pre>
        </div>
    </div>
    
    <script>
        let protectionEnabled = true;
        
        function toggleProtection() {
            protectionEnabled = !protectionEnabled;
            const button = event.target;
            if (protectionEnabled) {
                button.textContent = "禁用保护";
                document.removeEventListener("copy", preventCopy);
                document.addEventListener("copy", preventCopy);
            } else {
                button.textContent = "启用保护";
                document.removeEventListener("copy", preventCopy);
            }
        }
        
        function preventCopy(e) {
            if (protectionEnabled) {
                e.preventDefault();
                alert("复制操作已被阻止!");
            }
        }
        
        function testCopy() {
            const textarea = document.getElementById('test-textarea');
            textarea.focus();
            document.execCommand('paste');
        }
        
        function resetAll() {
            const textarea = document.getElementById('test-textarea');
            textarea.value = '';
            protectionEnabled = true;
            document.addEventListener("copy", preventCopy);
        }
        
        // 初始化
        document.addEventListener("copy", preventCopy);
    </script>
</body>
</html>

Open browser consoleTests

注意事项

  • user-select: none 只阻止选择,不能阻止复制已选中的内容
  • JavaScript 的 copy 事件可以完全阻止复制操作
  • 这种方法不能阻止用户通过开发者工具查看源代码
  • 建议谨慎使用,避免影响用户体验

面试官视角

该题考察对 CSS 和 JavaScript 结合使用的理解,是前端开发中的实用知识点。面试官通过此题可以了解候选人对用户体验和内容保护的考虑。

延伸阅读

三角形 border

答案

核心概念

在 CSS 中,可以使用多种方法来实现三角形。这些方法主要基于 CSS 的边框特性和几何变换。

方法一:使用边框

通过设置元素的边框来创建三角形,其中左右边框设为透明,底边框设置为你想要的颜色:

.triangle {
width: 0;
height: 0;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-bottom: 100px solid red;
}

方法二:使用伪元素

使用伪元素 ::before 来创建三角形,通过设置其边框的宽度和样式来实现:

.triangle {
position: relative;
width: 100px;
height: 100px;
}

.triangle:before {
content: "";
position: absolute;
top: 0;
left: 0;
border-width: 0 100px 100px 0;
border-style: solid;
border-color: red;
}

方法三:使用旋转

创建一个正方形元素,然后通过使用 transform 属性的 rotate 函数将其旋转45度:

.triangle {
width: 100px;
height: 100px;
background-color: red;
transform: rotate(45deg);
}

示例说明

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSS 三角形演示</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
            background-color: #f5f5f5;
        }
        
        .container {
            max-width: 1000px;
            margin: 0 auto;
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        
        .demo-section {
            margin: 20px 0;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 5px;
        }
        
        .triangle-container {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
            margin: 20px 0;
        }
        
        .triangle-item {
            text-align: center;
            padding: 15px;
            border: 1px solid #eee;
            border-radius: 5px;
            background: #f9f9f9;
        }
        
        .triangle {
            margin: 10px auto;
        }
        
        /* 方法一:使用边框 */
        .triangle-border {
            width: 0;
            height: 0;
            border-left: 50px solid transparent;
            border-right: 50px solid transparent;
            border-bottom: 100px solid #ff6b6b;
        }
        
        .triangle-border-down {
            width: 0;
            height: 0;
            border-left: 50px solid transparent;
            border-right: 50px solid transparent;
            border-top: 100px solid #4ecdc4;
        }
        
        .triangle-border-left {
            width: 0;
            height: 0;
            border-top: 50px solid transparent;
            border-bottom: 50px solid transparent;
            border-right: 100px solid #45b7d1;
        }
        
        .triangle-border-right {
            width: 0;
            height: 0;
            border-top: 50px solid transparent;
            border-bottom: 50px solid transparent;
            border-left: 100px solid #96ceb4;
        }
        
        /* 方法二:使用伪元素 */
        .triangle-pseudo {
            position: relative;
            width: 100px;
            height: 100px;
        }
        
        .triangle-pseudo:before {
            content: "";
            position: absolute;
            top: 0;
            left: 0;
            border-width: 0 100px 100px 0;
            border-style: solid;
            border-color: #ff6b6b;
        }
        
        /* 方法三:使用旋转 */
        .triangle-rotate {
            width: 100px;
            height: 100px;
            background-color: #4ecdc4;
            transform: rotate(45deg);
        }
        
        .triangle-rotate-container {
            width: 100px;
            height: 100px;
            overflow: hidden;
            position: relative;
        }
        
        .triangle-rotate-inner {
            width: 70px;
            height: 70px;
            background-color: #45b7d1;
            transform: rotate(45deg);
            position: absolute;
            top: 15px;
            left: 15px;
        }
        
        h2 {
            color: #333;
            border-bottom: 2px solid #4CAF50;
            padding-bottom: 5px;
        }
        
        .code-block {
            background: #f8f9fa;
            padding: 15px;
            border-radius: 5px;
            font-family: 'Courier New', monospace;
            margin: 10px 0;
            overflow-x: auto;
        }
        
        .method-title {
            font-weight: bold;
            color: #2c3e50;
            margin-bottom: 10px;
        }
        
        .direction-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
            margin: 20px 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>CSS 三角形创建方法演示</h1>
        
        <div class="demo-section">
            <h2>方法一:使用边框(Border Method)</h2>
            <p>通过设置元素的边框来创建三角形,其中部分边框设为透明:</p>
            
            <div class="triangle-container">
                <div class="triangle-item">
                    <div class="method-title">向上三角形</div>
                    <div class="triangle triangle-border"></div>
                    <div class="code-block">
                        .triangle-up {
  width: 0;
  height: 0;
  border-left: 50px solid transparent;
  border-right: 50px solid transparent;
  border-bottom: 100px solid red;
}
                    </div>
                </div>
                
                <div class="triangle-item">
                    <div class="method-title">向下三角形</div>
                    <div class="triangle triangle-border-down"></div>
                    <div class="code-block">
                        .triangle-down {
  width: 0;
  height: 0;
  border-left: 50px solid transparent;
  border-right: 50px solid transparent;
  border-top: 100px solid red;
}
                    </div>
                </div>
                
                <div class="triangle-item">
                    <div class="method-title">向左三角形</div>
                    <div class="triangle triangle-border-left"></div>
                    <div class="code-block">
                        .triangle-left {
  width: 0;
  height: 0;
  border-top: 50px solid transparent;
  border-bottom: 50px solid transparent;
  border-right: 100px solid red;
}
                    </div>
                </div>
                
                <div class="triangle-item">
                    <div class="method-title">向右三角形</div>
                    <div class="triangle triangle-border-right"></div>
                    <div class="code-block">
                        .triangle-right {
  width: 0;
  height: 0;
  border-top: 50px solid transparent;
  border-bottom: 50px solid transparent;
  border-left: 100px solid red;
}
                    </div>
                </div>
            </div>
        </div>
        
        <div class="demo-section">
            <h2>方法二:使用伪元素(Pseudo-element Method)</h2>
            <p>使用伪元素 `::before` 来创建三角形:</p>
            
            <div class="triangle-container">
                <div class="triangle-item">
                    <div class="method-title">伪元素三角形</div>
                    <div class="triangle triangle-pseudo"></div>
                    <div class="code-block">
                        .triangle-pseudo {
  position: relative;
  width: 100px;
  height: 100px;
}

.triangle-pseudo:before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  border-width: 0 100px 100px 0;
  border-style: solid;
  border-color: red;
}
                    </div>
                </div>
            </div>
        </div>
        
        <div class="demo-section">
            <h2>方法三:使用旋转(Transform Method)</h2>
            <p>创建一个正方形元素,然后通过旋转来形成三角形:</p>
            
            <div class="triangle-container">
                <div class="triangle-item">
                    <div class="method-title">旋转正方形</div>
                    <div class="triangle triangle-rotate"></div>
                    <div class="code-block">
                        .triangle-rotate {
  width: 100px;
  height: 100px;
  background-color: red;
  transform: rotate(45deg);
}
                    </div>
                </div>
                
                <div class="triangle-item">
                    <div class="method-title">裁剪旋转</div>
                    <div class="triangle triangle-rotate-container">
                        <div class="triangle-rotate-inner"></div>
                    </div>
                    <div class="code-block">
                        .triangle-rotate-container {
  width: 100px;
  height: 100px;
  overflow: hidden;
}

.triangle-rotate-inner {
  width: 70px;
  height: 70px;
  background-color: red;
  transform: rotate(45deg);
  position: absolute;
  top: 15px;
  left: 15px;
}
                    </div>
                </div>
            </div>
        </div>
        
        <div class="demo-section">
            <h2>各种方向的三角形</h2>
            <div class="direction-grid">
                <div class="triangle-item">
                    <div class="method-title">向上</div>
                    <div class="triangle triangle-border"></div>
                </div>
                <div class="triangle-item">
                    <div class="method-title">向下</div>
                    <div class="triangle triangle-border-down"></div>
                </div>
                <div class="triangle-item">
                    <div class="method-title">向左</div>
                    <div class="triangle triangle-border-left"></div>
                </div>
                <div class="triangle-item">
                    <div class="method-title">向右</div>
                    <div class="triangle triangle-border-right"></div>
                </div>
            </div>
        </div>
        
        <div class="demo-section">
            <h2>使用场景</h2>
            <ul>
                <li><strong>下拉箭头</strong>:用于指示下拉菜单的方向</li>
                <li><strong>气泡提示</strong>:聊天框或提示框的指向箭头</li>
                <li><strong>导航指示</strong>:面包屑导航或步骤指示器</li>
                <li><strong>装饰元素</strong>:页面装饰或图标的一部分</li>
            </ul>
        </div>
    </div>
</body>
</html>

Open browser consoleTests

各种方向三角形

/* 向上三角形 */
.triangle-up {
width: 0;
height: 0;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-bottom: 100px solid red;
}

/* 向下三角形 */
.triangle-down {
width: 0;
height: 0;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-top: 100px solid red;
}

/* 向左三角形 */
.triangle-left {
width: 0;
height: 0;
border-top: 50px solid transparent;
border-bottom: 50px solid transparent;
border-right: 100px solid red;
}

/* 向右三角形 */
.triangle-right {
width: 0;
height: 0;
border-top: 50px solid transparent;
border-bottom: 50px solid transparent;
border-left: 100px solid red;
}

面试官视角

该题考察对 CSS 边框特性和几何变换的理解,是前端开发中的实用知识点。面试官通过此题可以了解候选人对 CSS 技巧的掌握程度。

延伸阅读

CSS3实现卡片翻转?

答案

核心概念

CSS3 卡片翻转效果主要通过 transform 属性实现,利用 3D 变换和过渡动画来创建翻转效果。这种技术常用于展示卡片的正反面信息。

实现原理

  1. 3D 变换:使用 transform-style: preserve-3d 保持 3D 效果
  2. 背面隐藏:使用 backface-visibility: hidden 隐藏背面
  3. 过渡动画:使用 transition 实现平滑的翻转动画
  4. 旋转控制:通过 transform: rotateY() 控制翻转角度

基本实现

.card-container {
perspective: 1000px;
width: 200px;
height: 300px;
}

.card {
position: relative;
width: 100%;
height: 100%;
transform-style: preserve-3d;
transition: transform 0.6s;
cursor: pointer;
}

.card.flipped {
transform: rotateY(180deg);
}

.card-front,
.card-back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
color: white;
}

.card-front {
background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
}

.card-back {
background: linear-gradient(45deg, #45b7d1, #96ceb4);
transform: rotateY(180deg);
}

示例说明

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSS3 卡片翻转演示</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
            background-color: #f5f5f5;
        }
        
        .container {
            max-width: 1000px;
            margin: 0 auto;
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        
        .demo-section {
            margin: 20px 0;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 5px;
        }
        
        .cards-container {
            display: flex;
            flex-wrap: wrap;
            gap: 30px;
            justify-content: center;
            margin: 20px 0;
        }
        
        .card-container {
            perspective: 1000px;
            width: 200px;
            height: 300px;
        }
        
        .card {
            position: relative;
            width: 100%;
            height: 100%;
            transform-style: preserve-3d;
            transition: transform 0.6s;
            cursor: pointer;
        }
        
        .card.flipped {
            transform: rotateY(180deg);
        }
        
        .card-front,
        .card-back {
            position: absolute;
            width: 100%;
            height: 100%;
            backface-visibility: hidden;
            border-radius: 10px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            font-size: 18px;
            color: white;
            text-align: center;
            padding: 20px;
            box-shadow: 0 4px 8px rgba(0,0,0,0.2);
        }
        
        .card-front {
            background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
        }
        
        .card-back {
            background: linear-gradient(45deg, #45b7d1, #96ceb4);
            transform: rotateY(180deg);
        }
        
        .card-title {
            font-size: 24px;
            font-weight: bold;
            margin-bottom: 10px;
        }
        
        .card-content {
            font-size: 14px;
            line-height: 1.4;
        }
        
        .controls {
            margin: 20px 0;
            padding: 15px;
            background: #e8f4fd;
            border-radius: 5px;
            text-align: center;
        }
        
        button {
            margin: 5px;
            padding: 8px 16px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        
        button:hover {
            background-color: #45a049;
        }
        
        h2 {
            color: #333;
            border-bottom: 2px solid #4CAF50;
            padding-bottom: 5px;
        }
        
        .code-block {
            background: #f8f9fa;
            padding: 15px;
            border-radius: 5px;
            font-family: 'Courier New', monospace;
            margin: 10px 0;
            overflow-x: auto;
        }
        
        .flip-direction {
            margin-top: 10px;
            font-size: 12px;
            opacity: 0.8;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>CSS3 卡片翻转演示</h1>
        
        <div class="demo-section">
            <h2>基本翻转效果</h2>
            <p>点击卡片查看翻转效果:</p>
            
            <div class="cards-container">
                <div class="card-container">
                    <div class="card" onclick="toggleFlip(this)">
                        <div class="card-front">
                            <div class="card-title">正面</div>
                            <div class="card-content">
                                这是卡片的正面内容<br>
                                点击查看背面
                            </div>
                        </div>
                        <div class="card-back">
                            <div class="card-title">背面</div>
                            <div class="card-content">
                                这是卡片的背面内容<br>
                                再次点击返回正面
                            </div>
                        </div>
                    </div>
                    <div class="flip-direction">Y轴翻转</div>
                </div>
                
                <div class="card-container">
                    <div class="card" onclick="toggleFlipX(this)">
                        <div class="card-front">
                            <div class="card-title">正面</div>
                            <div class="card-content">
                                这是卡片的正面内容<br>
                                点击查看背面
                            </div>
                        </div>
                        <div class="card-back">
                            <div class="card-title">背面</div>
                            <div class="card-content">
                                这是卡片的背面内容<br>
                                再次点击返回正面
                            </div>
                        </div>
                    </div>
                    <div class="flip-direction">X轴翻转</div>
                </div>
            </div>
        </div>
        
        <div class="controls">
            <h3>控制面板</h3>
            <button onclick="flipAll()">翻转所有卡片</button>
            <button onclick="resetAll()">重置所有卡片</button>
            <button onclick="showCode()">显示代码</button>
        </div>
        
        <div class="demo-section" id="code-section" style="display: none;">
            <h2>实现代码</h2>
            <div class="code-block">
                <h3>HTML 结构:</h3>
                <pre><code>&lt;div class="card-container"&gt;
  &lt;div class="card"&gt;
    &lt;div class="card-front"&gt;正面内容&lt;/div&gt;
    &lt;div class="card-back"&gt;背面内容&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</code></pre>
                
                <h3>CSS 样式:</h3>
                <pre><code>.card-container {
  perspective: 1000px;
  width: 200px;
  height: 300px;
}

.card {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.6s;
  cursor: pointer;
}

.card.flipped {
  transform: rotateY(180deg);
}

.card-front,
.card-back {
  position: absolute;
  width: 100%;
  height: 100%;
  backface-visibility: hidden;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.card-back {
  transform: rotateY(180deg);
}</code></pre>
                
                <h3>JavaScript 控制:</h3>
                <pre><code>function toggleFlip(card) {
  card.classList.toggle('flipped');
}</code></pre>
            </div>
        </div>
        
        <div class="demo-section">
            <h2>关键属性说明</h2>
            <ul>
                <li><strong>perspective</strong>:设置 3D 视角距离,值越小效果越明显</li>
                <li><strong>transform-style: preserve-3d</strong>:保持 3D 变换效果</li>
                <li><strong>backface-visibility: hidden</strong>:隐藏元素背面</li>
                <li><strong>transition</strong>:添加过渡动画效果</li>
                <li><strong>transform: rotateY(180deg)</strong>:Y轴旋转180度</li>
            </ul>
        </div>
    </div>
    
    <script>
        function toggleFlip(card) {
            card.classList.toggle('flipped');
        }
        
        function toggleFlipX(card) {
            if (card.classList.contains('flipped')) {
                card.style.transform = 'rotateX(0deg)';
                card.classList.remove('flipped');
            } else {
                card.style.transform = 'rotateX(180deg)';
                card.classList.add('flipped');
            }
        }
        
        function flipAll() {
            const cards = document.querySelectorAll('.card');
            cards.forEach(card => {
                card.classList.add('flipped');
            });
        }
        
        function resetAll() {
            const cards = document.querySelectorAll('.card');
            cards.forEach(card => {
                card.classList.remove('flipped');
                card.style.transform = '';
            });
        }
        
        function showCode() {
            const codeSection = document.getElementById('code-section');
            if (codeSection.style.display === 'none') {
                codeSection.style.display = 'block';
            } else {
                codeSection.style.display = 'none';
            }
        }
    </script>
</body>
</html>

Open browser consoleTests

高级效果

多轴翻转

.card.flipped-x {
transform: rotateX(180deg);
}

.card.flipped-y {
transform: rotateY(180deg);
}

.card.flipped-z {
transform: rotateZ(180deg);
}

3D 翻转

.card.flipped-3d {
transform: rotateX(180deg) rotateY(180deg);
}

面试官视角

该题考察对 CSS3 3D 变换和动画的理解,是前端开发中的高级知识点。面试官通过此题可以了解候选人对现代 CSS 技术的掌握程度。

延伸阅读

常见布局实现

答案

核心概念

CSS 布局是前端开发的基础技能,常见的布局包括三栏布局、圣杯布局、双飞翼布局等。这些布局主要解决页面结构的基本需求。

三栏布局

三栏布局是最常见的页面布局,左右两栏固定宽度,中间栏自适应。

方法一:Flexbox 布局

.container {
display: flex;
min-height: 100vh;
}

.left, .right {
width: 200px;
background: #f0f0f0;
}

.center {
flex: 1;
background: #e0e0e0;
}

方法二:Grid 布局

.container {
display: grid;
grid-template-columns: 200px 1fr 200px;
min-height: 100vh;
}

.left, .right {
background: #f0f0f0;
}

.center {
background: #e0e0e0;
}

圣杯布局

圣杯布局是一种经典的三栏布局,要求中间栏优先渲染,左右两栏固定宽度。

.container {
padding: 0 200px;
}

.center {
float: left;
width: 100%;
background: #e0e0e0;
}

.left, .right {
float: left;
width: 200px;
margin-left: -100%;
position: relative;
left: -200px;
background: #f0f0f0;
}

.right {
left: 200px;
margin-left: -200px;
}

.container::after {
content: "";
display: table;
clear: both;
}

示例说明

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSS 常见布局演示</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
            background-color: #f5f5f5;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        
        .demo-section {
            margin: 20px 0;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 5px;
        }
        
        .layout-container {
            margin: 20px 0;
            border: 2px solid #333;
            min-height: 200px;
        }
        
        .layout-title {
            background: #333;
            color: white;
            padding: 10px;
            font-weight: bold;
        }
        
        .left, .right {
            background: #f0f0f0;
            padding: 20px;
            text-align: center;
            font-weight: bold;
        }
        
        .center {
            background: #e0e0e0;
            padding: 20px;
            text-align: center;
            font-weight: bold;
        }
        
        /* Flexbox 三栏布局 */
        .flex-layout {
            display: flex;
            min-height: 200px;
        }
        
        .flex-layout .left,
        .flex-layout .right {
            width: 200px;
            flex-shrink: 0;
        }
        
        .flex-layout .center {
            flex: 1;
        }
        
        /* Grid 三栏布局 */
        .grid-layout {
            display: grid;
            grid-template-columns: 200px 1fr 200px;
            min-height: 200px;
        }
        
        /* 圣杯布局 */
        .holy-grail {
            padding: 0 200px;
        }
        
        .holy-grail .center {
            float: left;
            width: 100%;
        }
        
        .holy-grail .left,
        .holy-grail .right {
            float: left;
            width: 200px;
            margin-left: -100%;
            position: relative;
            left: -200px;
        }
        
        .holy-grail .right {
            left: 200px;
            margin-left: -200px;
        }
        
        .holy-grail::after {
            content: "";
            display: table;
            clear: both;
        }
        
        /* 居中布局 */
        .center-demo {
            height: 150px;
            border: 2px solid #333;
            margin: 20px 0;
            position: relative;
        }
        
        .text-center {
            text-align: center;
            padding: 20px;
            background: #e8f5e8;
        }
        
        .block-center {
            width: 200px;
            margin: 0 auto;
            padding: 20px;
            background: #ffe8e8;
            text-align: center;
        }
        
        .flex-center {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100%;
        }
        
        .flex-center .item {
            background: #fff3cd;
            padding: 20px;
            text-align: center;
        }
        
        .absolute-center {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: #e8f4fd;
            padding: 20px;
            text-align: center;
        }
        
        h2 {
            color: #333;
            border-bottom: 2px solid #4CAF50;
            padding-bottom: 5px;
        }
        
        .code-block {
            background: #f8f9fa;
            padding: 15px;
            border-radius: 5px;
            font-family: 'Courier New', monospace;
            margin: 10px 0;
            overflow-x: auto;
        }
        
        .controls {
            margin: 20px 0;
            padding: 15px;
            background: #e8f4fd;
            border-radius: 5px;
            text-align: center;
        }
        
        button {
            margin: 5px;
            padding: 8px 16px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        
        button:hover {
            background-color: #45a049;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>CSS 常见布局演示</h1>
        
        <div class="demo-section">
            <h2>三栏布局 - Flexbox 方法</h2>
            <div class="layout-container">
                <div class="layout-title">Flexbox 三栏布局</div>
                <div class="flex-layout">
                    <div class="left">左侧栏<br>固定宽度 200px</div>
                    <div class="center">中间栏<br>自适应宽度</div>
                    <div class="right">右侧栏<br>固定宽度 200px</div>
                </div>
            </div>
            
            <div class="code-block">
                <h3>Flexbox 三栏布局代码:</h3>
                <pre><code>.container {
  display: flex;
  min-height: 200px;
}

.left, .right {
  width: 200px;
  flex-shrink: 0;
}

.center {
  flex: 1;
}</code></pre>
            </div>
        </div>
        
        <div class="demo-section">
            <h2>三栏布局 - Grid 方法</h2>
            <div class="layout-container">
                <div class="layout-title">Grid 三栏布局</div>
                <div class="grid-layout">
                    <div class="left">左侧栏<br>固定宽度 200px</div>
                    <div class="center">中间栏<br>自适应宽度</div>
                    <div class="right">右侧栏<br>固定宽度 200px</div>
                </div>
            </div>
            
            <div class="code-block">
                <h3>Grid 三栏布局代码:</h3>
                <pre><code>.container {
  display: grid;
  grid-template-columns: 200px 1fr 200px;
  min-height: 200px;
}</code></pre>
            </div>
        </div>
        
        <div class="demo-section">
            <h2>圣杯布局</h2>
            <div class="layout-container">
                <div class="layout-title">圣杯布局(中间栏优先渲染)</div>
                <div class="holy-grail">
                    <div class="center">中间栏<br>优先渲染,自适应宽度</div>
                    <div class="left">左侧栏<br>固定宽度 200px</div>
                    <div class="right">右侧栏<br>固定宽度 200px</div>
                </div>
            </div>
            
            <div class="code-block">
                <h3>圣杯布局代码:</h3>
                <pre><code>.container {
  padding: 0 200px;
}

.center {
  float: left;
  width: 100%;
}

.left, .right {
  float: left;
  width: 200px;
  margin-left: -100%;
  position: relative;
  left: -200px;
}

.right {
  left: 200px;
  margin-left: -200px;
}</code></pre>
            </div>
        </div>
        
        <div class="demo-section">
            <h2>居中布局方法</h2>
            
            <h3>1. 行内元素水平居中</h3>
            <div class="center-demo">
                <div class="text-center">
                    <span>这是行内元素</span>
                    <a href="#">链接元素</a>
                    <span>文本居中显示</span>
                </div>
            </div>
            
            <h3>2. 块状元素水平居中</h3>
            <div class="center-demo">
                <div class="block-center">
                    块状元素居中<br>
                    margin: 0 auto
                </div>
            </div>
            
            <h3>3. Flexbox 居中</h3>
            <div class="center-demo">
                <div class="flex-center">
                    <div class="item">
                        Flexbox 居中<br>
                        justify-content: center<br>
                        align-items: center
                    </div>
                </div>
            </div>
            
            <h3>4. 绝对定位居中</h3>
            <div class="center-demo">
                <div class="absolute-center">
                    绝对定位居中<br>
                    top: 50%; left: 50%<br>
                    transform: translate(-50%, -50%)
                </div>
            </div>
        </div>
        
        <div class="controls">
            <h3>布局特点对比</h3>
            <table style="width: 100%; border-collapse: collapse; margin: 20px 0;">
                <thead>
                    <tr style="background: #f0f0f0;">
                        <th style="border: 1px solid #ddd; padding: 10px;">布局方法</th>
                        <th style="border: 1px solid #ddd; padding: 10px;">优点</th>
                        <th style="border: 1px solid #ddd; padding: 10px;">缺点</th>
                        <th style="border: 1px solid #ddd; padding: 10px;">兼容性</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td style="border: 1px solid #ddd; padding: 10px;">Flexbox</td>
                        <td style="border: 1px solid #ddd; padding: 10px;">简单易用,响应式好</td>
                        <td style="border: 1px solid #ddd; padding: 10px;">IE9 以下不支持</td>
                        <td style="border: 1px solid #ddd; padding: 10px;">现代浏览器</td>
                    </tr>
                    <tr>
                        <td style="border: 1px solid #ddd; padding: 10px;">Grid</td>
                        <td style="border: 1px solid #ddd; padding: 10px;">功能强大,二维布局</td>
                        <td style="border: 1px solid #ddd; padding: 10px;">IE 不支持</td>
                        <td style="border: 1px solid #ddd; padding: 10px;">现代浏览器</td>
                    </tr>
                    <tr>
                        <td style="border: 1px solid #ddd; padding: 10px;">圣杯布局</td>
                        <td style="border: 1px solid #ddd; padding: 10px;">兼容性好,中间优先</td>
                        <td style="border: 1px solid #ddd; padding: 10px;">代码复杂,维护困难</td>
                        <td style="border: 1px solid #ddd; padding: 10px;">所有浏览器</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
</body>
</html>

Open browser consoleTests

居中布局方法

行内元素水平居中

.text-center {
text-align: center;
}

块状元素水平居中

.block-center {
margin: 0 auto;
}

Flexbox 居中

.flex-center {
display: flex;
justify-content: center;
align-items: center;
}

绝对定位居中

.absolute-center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}

面试官视角

该题考察对 CSS 布局技术的理解,是前端开发的基础知识点。面试官通过此题可以了解候选人对布局原理和实现方法的掌握程度。

延伸阅读

实现阿拉伯数字转中文

答案

核心概念

将阿拉伯数字转换成中文数字,主要考虑到以下几个转换规则:

  1. 基本数字:0-9 对应的汉字数字
  2. 单位:十、百、千、万、亿等
  3. 规则:数字从右到左,每 4 位一小节,小节内部和小节之间的转换规则

实现思路

  1. 将阿拉伯数字分解成单个数字,从右到左进行处理
  2. 对每 4 位数字进行处理,即一个小节,处理完再根据小节的位置添加对应的单位(万、亿等)
  3. 处理当前小节内部的数字,并添加十、百、千的单位,注意去除连续的零,并且在必要时加入"零"字
  4. 将各个小节合并得到最终结果

示例实现

const number2text = (number, type = 'upper') => {
// 配置
const confs = {
lower: {
num: ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'],
unit: ['', '十', '百', '千', '万'],
level: ['', '万', '亿']
},
upper: {
num: ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'],
unit: ['', '拾', '佰', '仟'],
level: ['', '万', '亿']
}
}

// 处理逻辑...
return result
}

面试官视角

该题考察对算法和字符串处理的理解,是前端开发中的实用知识点。面试官通过此题可以了解候选人对复杂逻辑的处理能力。

延伸阅读

实现 table header 吸顶

答案

核心概念

Table header 吸顶是指当页面滚动时,表格头部保持在视窗顶部,不会随着滚动而消失,提升表格的用户体验和易用性。

实现方法

方法一:使用 position: sticky

th {
position: sticky;
top: 0;
background-color: #fff;
z-index: 1;
}

方法二:使用 CSS transform

th {
position: relative;
z-index: 1;
}

thead {
position: fixed;
top: 0;
visibility: hidden;
z-index: 2;
transform: translateY(0);
}

tbody {
margin-top: 50px;
}

方法三:JavaScript + CSS

<div class="table-wrapper">
<table>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
</tr>
</thead>
<tbody>
<!-- 表格内容 -->
</tbody>
</table>
</div>

<script>
window.onscroll = function() {
var header = document.querySelector(".table-wrapper thead");
if (window.pageYOffset > 150) {
header.classList.add("sticky");
} else {
header.classList.remove("sticky");
}
};
</script>

<style>
.table-wrapper {
position: relative;
}

.table-wrapper thead {
position: fixed;
top: 0;
z-index: 1;
background-color: #fff;
}

.table-wrapper th {
height: 50px;
}

.table-wrapper.sticky thead {
position: absolute;
top: 50px;
}
</style>

示例说明

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Table Header 吸顶演示</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            background-color: #f5f5f5;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            padding: 20px;
        }
        
        .demo-section {
            margin: 20px 0;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 5px;
        }
        
        .table-wrapper {
            margin: 20px 0;
            border: 1px solid #ddd;
            border-radius: 5px;
            overflow: hidden;
        }
        
        table {
            width: 100%;
            border-collapse: collapse;
            background: white;
        }
        
        th {
            background: #4CAF50;
            color: white;
            padding: 15px;
            text-align: left;
            font-weight: bold;
            border-bottom: 2px solid #45a049;
        }
        
        td {
            padding: 12px 15px;
            border-bottom: 1px solid #ddd;
        }
        
        tr:hover {
            background-color: #f5f5f5;
        }
        
        /* 方法一:position: sticky */
        .sticky-table th {
            position: sticky;
            top: 0;
            z-index: 10;
        }
        
        /* 方法二:JavaScript 控制 */
        .js-sticky-table {
            position: relative;
        }
        
        .js-sticky-table thead {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            z-index: 100;
            background: #4CAF50;
            display: none;
        }
        
        .js-sticky-table.sticky thead {
            display: table-header-group;
        }
        
        .js-sticky-table.sticky tbody {
            margin-top: 60px;
        }
        
        .controls {
            margin: 20px 0;
            padding: 15px;
            background: #e8f4fd;
            border-radius: 5px;
            text-align: center;
        }
        
        button {
            margin: 5px;
            padding: 8px 16px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        
        button:hover {
            background-color: #45a049;
        }
        
        h2 {
            color: #333;
            border-bottom: 2px solid #4CAF50;
            padding-bottom: 5px;
        }
        
        .code-block {
            background: #f8f9fa;
            padding: 15px;
            border-radius: 5px;
            font-family: 'Courier New', monospace;
            margin: 10px 0;
            overflow-x: auto;
        }
        
        .scroll-hint {
            background: #fff3cd;
            padding: 10px;
            border-radius: 5px;
            margin: 10px 0;
            text-align: center;
            color: #856404;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Table Header 吸顶演示</h1>
        
        <div class="scroll-hint">
            <strong>提示:</strong>向下滚动页面查看吸顶效果
        </div>
        
        <div class="demo-section">
            <h2>方法一:CSS position: sticky</h2>
            <p>使用 CSS 的 <code>position: sticky</code> 属性实现吸顶效果:</p>
            
            <div class="table-wrapper">
                <table class="sticky-table">
                    <thead>
                        <tr>
                            <th>姓名</th>
                            <th>年龄</th>
                            <th>职位</th>
                            <th>部门</th>
                            <th>入职时间</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr><td>张三</td><td>28</td><td>前端工程师</td><td>技术部</td><td>2020-01-15</td></tr>
                        <tr><td>李四</td><td>32</td><td>产品经理</td><td>产品部</td><td>2019-03-20</td></tr>
                        <tr><td>王五</td><td>25</td><td>UI设计师</td><td>设计部</td><td>2021-06-10</td></tr>
                        <tr><td>赵六</td><td>30</td><td>后端工程师</td><td>技术部</td><td>2018-09-05</td></tr>
                        <tr><td>钱七</td><td>27</td><td>测试工程师</td><td>技术部</td><td>2020-11-12</td></tr>
                        <tr><td>孙八</td><td>29</td><td>运营专员</td><td>运营部</td><td>2021-02-28</td></tr>
                        <tr><td>周九</td><td>31</td><td>市场经理</td><td>市场部</td><td>2019-07-15</td></tr>
                        <tr><td>吴十</td><td>26</td><td>数据分析师</td><td>数据部</td><td>2020-08-20</td></tr>
                        <tr><td>郑十一</td><td>33</td><td>技术总监</td><td>技术部</td><td>2017-12-01</td></tr>
                        <tr><td>王十二</td><td>28</td><td>产品助理</td><td>产品部</td><td>2021-04-05</td></tr>
                    </tbody>
                </table>
            </div>
            
            <div class="code-block">
                <h3>CSS 代码:</h3>
                <pre><code>th {
  position: sticky;
  top: 0;
  z-index: 10;
  background: #4CAF50;
  color: white;
}</code></pre>
            </div>
        </div>
        
        <div class="demo-section">
            <h2>方法二:JavaScript + CSS</h2>
            <p>使用 JavaScript 监听滚动事件,动态添加 CSS 类:</p>
            
            <div class="table-wrapper js-sticky-table" id="js-sticky-table">
                <table>
                    <thead>
                        <tr>
                            <th>姓名</th>
                            <th>年龄</th>
                            <th>职位</th>
                            <th>部门</th>
                            <th>入职时间</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr><td>张三</td><td>28</td><td>前端工程师</td><td>技术部</td><td>2020-01-15</td></tr>
                        <tr><td>李四</td><td>32</td><td>产品经理</td><td>产品部</td><td>2019-03-20</td></tr>
                        <tr><td>王五</td><td>25</td><td>UI设计师</td><td>设计部</td><td>2021-06-10</td></tr>
                        <tr><td>赵六</td><td>30</td><td>后端工程师</td><td>技术部</td><td>2018-09-05</td></tr>
                        <tr><td>钱七</td><td>27</td><td>测试工程师</td><td>技术部</td><td>2020-11-12</td></tr>
                        <tr><td>孙八</td><td>29</td><td>运营专员</td><td>运营部</td><td>2021-02-28</td></tr>
                        <tr><td>周九</td><td>31</td><td>市场经理</td><td>市场部</td><td>2019-07-15</td></tr>
                        <tr><td>吴十</td><td>26</td><td>数据分析师</td><td>数据部</td><td>2020-08-20</td></tr>
                        <tr><td>郑十一</td><td>33</td><td>技术总监</td><td>技术部</td><td>2017-12-01</td></tr>
                        <tr><td>王十二</td><td>28</td><td>产品助理</td><td>产品部</td><td>2021-04-05</td></tr>
                    </tbody>
                </table>
            </div>
            
            <div class="code-block">
                <h3>JavaScript 代码:</h3>
                <pre><code>window.onscroll = function() {
  var table = document.querySelector(".js-sticky-table");
  var rect = table.getBoundingClientRect();
  
  if (rect.top <= 0) {
    table.classList.add("sticky");
  } else {
    table.classList.remove("sticky");
  }
};</code></pre>
            </div>
        </div>
        
        <div class="controls">
            <h3>控制面板</h3>
            <button onclick="toggleSticky()">切换吸顶效果</button>
            <button onclick="scrollToTable()">滚动到表格</button>
            <button onclick="resetScroll()">重置滚动</button>
        </div>
        
        <div class="demo-section">
            <h2>实现方法对比</h2>
            <table style="width: 100%; border-collapse: collapse;">
                <thead>
                    <tr style="background: #f0f0f0;">
                        <th style="border: 1px solid #ddd; padding: 10px;">方法</th>
                        <th style="border: 1px solid #ddd; padding: 10px;">优点</th>
                        <th style="border: 1px solid #ddd; padding: 10px;">缺点</th>
                        <th style="border: 1px solid #ddd; padding: 10px;">兼容性</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td style="border: 1px solid #ddd; padding: 10px;">position: sticky</td>
                        <td style="border: 1px solid #ddd; padding: 10px;">简单易用,性能好</td>
                        <td style="border: 1px solid #ddd; padding: 10px;">IE 不支持</td>
                        <td style="border: 1px solid #ddd; padding: 10px;">现代浏览器</td>
                    </tr>
                    <tr>
                        <td style="border: 1px solid #ddd; padding: 10px;">JavaScript + CSS</td>
                        <td style="border: 1px solid #ddd; padding: 10px;">兼容性好,控制灵活</td>
                        <td style="border: 1px solid #ddd; padding: 10px;">需要 JavaScript,性能稍差</td>
                        <td style="border: 1px solid #ddd; padding: 10px;">所有浏览器</td>
                    </tr>
                </tbody>
            </table>
        </div>
        
        <!-- 添加一些内容来增加页面高度 -->
        <div style="height: 1000px; background: linear-gradient(to bottom, #f0f0f0, #e0e0e0); padding: 20px; margin: 20px 0;">
            <h3>页面内容区域</h3>
            <p>向下滚动查看表格吸顶效果...</p>
            <p>这个区域用于增加页面高度,让滚动效果更明显。</p>
        </div>
    </div>
    
    <script>
        let stickyEnabled = true;
        
        function toggleSticky() {
            stickyEnabled = !stickyEnabled;
            const button = event.target;
            if (stickyEnabled) {
                button.textContent = "禁用吸顶效果";
                window.onscroll = handleScroll;
            } else {
                button.textContent = "启用吸顶效果";
                window.onscroll = null;
                document.querySelector('.js-sticky-table').classList.remove('sticky');
            }
        }
        
        function handleScroll() {
            if (!stickyEnabled) return;
            
            const table = document.querySelector(".js-sticky-table");
            const rect = table.getBoundingClientRect();
            
            if (rect.top <= 0) {
                table.classList.add("sticky");
            } else {
                table.classList.remove("sticky");
            }
        }
        
        function scrollToTable() {
            document.querySelector('.js-sticky-table').scrollIntoView({
                behavior: 'smooth'
            });
        }
        
        function resetScroll() {
            window.scrollTo({
                top: 0,
                behavior: 'smooth'
            });
        }
        
        // 初始化
        window.onscroll = handleScroll;
    </script>
</body>
</html>

Open browser consoleTests

面试官视角

该题考察对 CSS 定位和 JavaScript 交互的理解,是前端开发中的实用知识点。面试官通过此题可以了解候选人对用户体验优化的考虑。

延伸阅读

CSS 文档流 是什么概念?

答案

核心概念

CSS 的文档流(Document Flow)是指文档中元素按照其在 HTML 中出现的顺序自上而下布局的方式,也称为常规流(Normal Flow)或默认流。文档流定义了元素的布局顺序和定位方式,包括元素的位置、大小、间距等属性。

文档流规则

在文档流中,每个元素都会占据一定的空间并尽可能充满其包含块的宽度。每个元素的位置都会受到前面元素的影响,如果前面的元素发生位置变化,那么后面的元素的位置也会发生相应的变化。

元素类型

  1. 块级元素:块级元素会独占一行,并在前面自动添加一个垂直间距。例如:<p><div><h1>

  2. 行内元素:行内元素会在一行中排列,并且宽度根据内容自适应。例如:<a><span><img>

  3. 行内块级元素:行内块级元素与行内元素类似,但是它可以设置宽度、高度等块级元素的属性。例如:<input><button><textarea>

脱离文档流

当元素设置以下属性时会脱离文档流:

  • position: absolute
  • position: fixed
  • float: left/right

面试官视角

该题考察对 CSS 布局基础概念的理解,是前端面试的必考知识点。面试官通过此题可以了解候选人对 CSS 布局原理的掌握程度。

延伸阅读

CSS 中 position 常见属性有哪些,大概讲一下?

答案

核心概念

CSS 中 position 属性用于指定元素的定位方式,它决定了元素在页面中的定位规则和布局行为。

常见属性值

  1. static(默认值)

    • 元素在文档流中正常排列
    • 不能通过 toprightbottomleft 属性进行偏移
  2. relative(相对定位)

    • 元素在文档流中正常排列
    • 可以通过设置 toprightbottomleft 属性相对于其正常位置进行偏移
    • 不会影响其它元素的位置
  3. absolute(绝对定位)

    • 元素脱离文档流
    • 相对于最近的非 static 定位的祖先元素进行定位
    • 如果没有则相对于 <html> 元素进行定位
    • 通过设置 toprightbottomleft 属性进行偏移
  4. fixed(固定定位)

    • 元素脱离文档流
    • 相对于浏览器窗口进行定位
    • 始终保持在窗口的固定位置,不会随页面滚动而滚动
    • 通过设置 toprightbottomleft 属性进行偏移
  5. sticky(粘性定位)

    • 元素在文档流中正常排列
    • 当元素滚动到指定的位置时,停止滚动并固定在该位置
    • 直到其祖先元素发生滚动时才会取消固定
    • 通过设置 toprightbottomleft 属性和 z-index 属性进行设置

示例说明

面试官视角

该题考察对 CSS 定位机制的理解,是前端开发的基础知识点。面试官通过此题可以了解候选人对 CSS 布局原理的掌握程度。

延伸阅读

未知高度和宽度元素的水平垂直居中的方案有哪些?

答案

核心概念

未知高度和宽度元素的水平垂直居中是前端开发中的常见需求,有多种实现方案,每种方案都有其适用场景和优缺点。

实现方案

方案一:Flexbox 布局

#container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}

#center {
/* 元素内容 */
}

方案二:Grid 布局

#container {
display: grid;
place-items: center;
height: 100vh;
}

#center {
/* 元素内容 */
}

方案三:绝对定位 + transform

#container {
position: relative;
height: 100vh;
}

#center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}

方案四:table-cell 布局

#container {
display: table-cell;
text-align: center;
vertical-align: middle;
height: 100vh;
}

#center {
display: inline-block;
}

方案五:绝对定位 + margin auto

#container {
position: relative;
height: 100vh;
}

#center {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
width: fit-content;
height: fit-content;
}

示例说明

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSS 居中布局演示</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 20px;
            background: #f5f5f5;
        }
        
        .demo-section {
            margin: 30px 0;
            padding: 20px;
            background: white;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        
        .demo-container {
            height: 200px;
            border: 2px dashed #007bff;
            margin: 15px 0;
            position: relative;
            background: #f8f9fa;
        }
        
        .centered-box {
            width: 100px;
            height: 60px;
            background: #007bff;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
            text-align: center;
            border-radius: 4px;
        }
        
        .method-title {
            color: #495057;
            font-weight: bold;
            margin-bottom: 10px;
        }
        
        .method-desc {
            color: #6c757d;
            font-size: 14px;
            margin-bottom: 10px;
        }
        
        /* 1. Flexbox 居中 */
        .flex-center {
            display: flex;
            align-items: center;
            justify-content: center;
        }
        
        /* 2. Grid 居中 */
        .grid-center {
            display: grid;
            place-items: center;
        }
        
        /* 3. 绝对定位 + transform */
        .absolute-center {
            position: relative;
        }
        
        .absolute-center .centered-box {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
        }
        
        /* 4. 绝对定位 + margin auto */
        .margin-auto-center {
            position: relative;
        }
        
        .margin-auto-center .centered-box {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            margin: auto;
            width: 100px;
            height: 60px;
        }
        
        /* 5. 行内元素居中 */
        .inline-center {
            text-align: center;
        }
        
        .inline-center .centered-box {
            display: inline-block;
        }
        
        /* 6. 表格居中 */
        .table-center {
            display: table;
            width: 100%;
            height: 100%;
        }
        
        .table-center .centered-box {
            display: table-cell;
            vertical-align: middle;
            text-align: center;
            width: 100px;
            height: 60px;
        }
        
        /* 7. 垂直居中 - line-height */
        .line-height-center {
            line-height: 200px;
            text-align: center;
        }
        
        .line-height-center .centered-box {
            display: inline-block;
            vertical-align: middle;
            line-height: normal;
        }
        
        /* 8. 未知尺寸元素居中 */
        .unknown-size-center {
            position: relative;
        }
        
        .unknown-size-center .centered-box {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: auto;
            height: auto;
            min-width: 100px;
            min-height: 60px;
            padding: 10px;
        }
        
        .code-example {
            background: #f8f9fa;
            border: 1px solid #e9ecef;
            border-radius: 4px;
            padding: 15px;
            margin: 10px 0;
            font-family: 'Courier New', monospace;
            font-size: 14px;
            overflow-x: auto;
        }
        
        .comparison-table {
            width: 100%;
            border-collapse: collapse;
            margin: 20px 0;
        }
        
        .comparison-table th,
        .comparison-table td {
            border: 1px solid #dee2e6;
            padding: 8px;
            text-align: left;
        }
        
        .comparison-table th {
            background: #f8f9fa;
            font-weight: bold;
        }
        
        .pros {
            color: #28a745;
        }
        
        .cons {
            color: #dc3545;
        }
    </style>
</head>
<body>
    <h1>CSS 居中布局演示</h1>
    
    <div class="demo-section">
        <h2>水平垂直居中方法</h2>
        
        <!-- Flexbox 居中 -->
        <div class="method-title">1. Flexbox 居中(推荐)</div>
        <div class="method-desc">使用 display: flex 配合 align-items 和 justify-content 实现居中</div>
        <div class="demo-container flex-center">
            <div class="centered-box">Flexbox<br>居中</div>
        </div>
        <div class="code-example">
.container {
  display: flex;
  align-items: center;
  justify-content: center;
}
        </div>
        
        <!-- Grid 居中 -->
        <div class="method-title">2. Grid 居中</div>
        <div class="method-desc">使用 display: grid 配合 place-items 实现居中</div>
        <div class="demo-container grid-center">
            <div class="centered-box">Grid<br>居中</div>
        </div>
        <div class="code-example">
.container {
  display: grid;
  place-items: center;
}
        </div>
        
        <!-- 绝对定位 + transform -->
        <div class="method-title">3. 绝对定位 + Transform</div>
        <div class="method-desc">使用绝对定位配合 transform: translate(-50%, -50%) 实现居中</div>
        <div class="demo-container absolute-center">
            <div class="centered-box">绝对定位<br>+ Transform</div>
        </div>
        <div class="code-example">
.container {
  position: relative;
}
.centered {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
        </div>
        
        <!-- 绝对定位 + margin auto -->
        <div class="method-title">4. 绝对定位 + Margin Auto</div>
        <div class="method-desc">使用绝对定位配合 margin: auto 实现居中(需要固定尺寸)</div>
        <div class="demo-container margin-auto-center">
            <div class="centered-box">绝对定位<br>+ Margin Auto</div>
        </div>
        <div class="code-example">
.centered {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: auto;
  width: 100px;
  height: 60px;
}
        </div>
    </div>
    
    <div class="demo-section">
        <h2>水平居中方法</h2>
        
        <!-- 行内元素居中 -->
        <div class="method-title">5. 行内元素居中</div>
        <div class="method-desc">使用 text-align: center 实现行内元素的水平居中</div>
        <div class="demo-container inline-center">
            <div class="centered-box">行内元素<br>居中</div>
        </div>
        <div class="code-example">
.container {
  text-align: center;
}
.centered {
  display: inline-block;
}
        </div>
        
        <!-- 表格居中 -->
        <div class="method-title">6. 表格居中</div>
        <div class="method-desc">使用 display: table 配合 vertical-align 实现居中</div>
        <div class="demo-container table-center">
            <div class="centered-box">表格<br>居中</div>
        </div>
        <div class="code-example">
.container {
  display: table;
}
.centered {
  display: table-cell;
  vertical-align: middle;
  text-align: center;
}
        </div>
        
        <!-- Line-height 居中 -->
        <div class="method-title">7. Line-height 居中</div>
        <div class="method-desc">使用 line-height 实现单行文本的垂直居中</div>
        <div class="demo-container line-height-center">
            <div class="centered-box">Line-height<br>居中</div>
        </div>
        <div class="code-example">
.container {
  line-height: 200px;
  text-align: center;
}
.centered {
  display: inline-block;
  vertical-align: middle;
  line-height: normal;
}
        </div>
    </div>
    
    <div class="demo-section">
        <h2>未知尺寸元素居中</h2>
        
        <div class="method-title">8. 未知尺寸元素居中</div>
        <div class="method-desc">使用绝对定位 + transform 实现未知尺寸元素的居中</div>
        <div class="demo-container unknown-size-center">
            <div class="centered-box">未知尺寸<br>元素居中<br>自适应内容</div>
        </div>
        <div class="code-example">
.centered {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: auto;
  height: auto;
  min-width: 100px;
  min-height: 60px;
}
        </div>
    </div>
    
    <div class="demo-section">
        <h2>方法对比</h2>
        <table class="comparison-table">
            <thead>
                <tr>
                    <th>方法</th>
                    <th>优点</th>
                    <th>缺点</th>
                    <th>适用场景</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>Flexbox</td>
                    <td class="pros">语法简洁、浏览器支持好、响应式友好</td>
                    <td class="cons">需要容器支持</td>
                    <td>现代布局首选方案</td>
                </tr>
                <tr>
                    <td>Grid</td>
                    <td class="pros">语法最简洁、功能强大</td>
                    <td class="cons">浏览器支持相对较新</td>
                    <td>复杂布局、现代项目</td>
                </tr>
                <tr>
                    <td>绝对定位 + Transform</td>
                    <td class="pros">兼容性好、支持未知尺寸</td>
                    <td class="cons">脱离文档流、代码相对复杂</td>
                    <td>弹窗、工具提示</td>
                </tr>
                <tr>
                    <td>绝对定位 + Margin</td>
                    <td class="pros">兼容性最好</td>
                    <td class="cons">需要固定尺寸、代码复杂</td>
                    <td>固定尺寸元素</td>
                </tr>
                <tr>
                    <td>行内元素居中</td>
                    <td class="pros">简单易用</td>
                    <td class="cons">只支持水平居中</td>
                    <td>文本、按钮等行内元素</td>
                </tr>
            </tbody>
        </table>
    </div>
    
    <div class="demo-section">
        <h2>最佳实践建议</h2>
        <ul>
            <li><strong>现代项目</strong>:优先使用 Flexbox 或 Grid</li>
            <li><strong>兼容性要求高</strong>:使用绝对定位 + transform</li>
            <li><strong>未知尺寸元素</strong>:使用绝对定位 + transform</li>
            <li><strong>行内元素</strong>:使用 text-align: center</li>
            <li><strong>单行文本</strong>:使用 line-height</li>
        </ul>
    </div>
    
    <script>
        // 添加交互效果
        document.addEventListener('DOMContentLoaded', function() {
            const boxes = document.querySelectorAll('.centered-box');
            
            boxes.forEach(box => {
                box.addEventListener('mouseenter', function() {
                    this.style.transform = this.style.transform ? 
                        this.style.transform + ' scale(1.1)' : 
                        'scale(1.1)';
                    this.style.transition = 'transform 0.2s ease';
                });
                
                box.addEventListener('mouseleave', function() {
                    this.style.transform = this.style.transform.replace(' scale(1.1)', '');
                });
            });
        });
    </script>
</body>
</html>

Open browser consoleTests

方案对比

方案优点缺点兼容性
Flexbox简单易用,响应式好IE9 以下不支持现代浏览器
Grid功能强大,代码简洁IE 不支持现代浏览器
Transform兼容性好,支持动画可能影响性能所有浏览器
Table-cell兼容性最好语义化不好所有浏览器
Margin auto兼容性好需要固定尺寸所有浏览器

面试官视角

该题考察对 CSS 布局技术的全面理解,是前端开发中的重要知识点。面试官通过此题可以了解候选人对不同布局方案的掌握程度和选择能力。

延伸阅读

CSS 中隐藏元素的方法有哪些?

opacity: 0visibility: hiddendisplay: none 都可以使元素不可见,但它们之间有一些区别。

  • opacity: 0:设置元素透明度为0,元素依然占据原来的空间,并且可以接收到鼠标事件。通常用于实现淡出效果。
  • visibility: hidden:元素不可见,但是仍然占据原来的空间,并且可以接收到鼠标事件。常用于实现菜单的展开和收起。
  • display: none:元素不可见,且不占据空间,也不接收鼠标事件。通常用于实现元素的隐藏和显示。

因为这三种属性的区别,它们在使用场景上也有所不同:

  • opacity: 0:适用于需要实现淡出效果的场景,比如弹出层的显示和隐藏。
  • visibility: hidden:适用于需要占据原来空间的元素,但不需要显示的场景,比如菜单的展开和收起。
  • display: none:适用于需要完全隐藏元素的场景,比如实现一个开关,点击开关后可以隐藏或者显示某个元素。

在 CSS 中,隐藏元素可以通过多种方式实现,每种方式有其特定的使用场景。这里列出了一些常用的方法:

  1. display: none;

完全移除元素,使其不占据任何空间,也不会在文档流中占位。元素及其所有子元素都不会显示。

.element {
display: none;
}
  1. visibility: hidden;

使元素不可见,但它仍然占据原来的空间和位置。与 display: none; 不同,visibility: hidden; 不会影响文档流的布局。

.element {
visibility: hidden;
}
  1. opacity: 0;

设置元素透明度为 0,使其完全透明。元素仍然占据空间,并且可以与之互动(例如,点击),除非你另外禁用了元素的互动能力。

.element {
opacity: 0;
}
  1. 使用绝对定位

将元素移出视图区域,例如设置一个非常大的负边距。

.element {
position: absolute;
left: -9999px;
}

或者使用 topbottom,将其定位到视窗外部。

  1. clipclip-path

通过剪裁,使元素的某些部分不可见。clip-path 可以更灵活地定义哪些部分可见。

.element {
clip-path: circle(0);
}
  1. overflow: hidden; 与尺寸设置

设置元素宽高为 0,并设置 overflowhidden,这将隐藏元素内容。

.element {
width: 0;
height: 0;
overflow: hidden;
}
  1. 将元素的 heightwidth 设置为 0 并结合 overflow: hidden

如果你还想保留某些边框或轮廓的样式,可能希望使用 widthheight0 的方法,加上 overflow: hidden 防止内容外泄。

.element {
width: 0;
height: 0;
overflow: hidden;
}

应用场景和选择

  • 从 DOM 中完全移除元素display: none; 适合完全从文档流中移除元素的场景。
  • 仍需要保留位置visibility: hidden; 适合需要隐藏元素但保留其占位的场景。
  • 逐渐隐藏opacity: 0; 适合需要渐变动画效果的场景。
  • 临时移除视野或隐藏内容的特定部分:使用定位或 clip-path 方法。

css 实现打字机效果

主要是对 css 动画的一个实际应用考察

以下是一个使用 CSS 实现简单打字机效果的示例代码:

<!DOCTYPE html>
<html lang="en">
<head>
<style>
.typewriter {
width: 300px;
border-right: 4px solid black;
animation: typing 4s steps(30), blink 0.5s step-end infinite;
white-space: nowrap;
overflow: hidden;
}

@keyframes typing {
from {
width: 0;
}
to {
width: 300px;
}
}

@keyframes blink {
50% {
border-color: transparent;
}
}
</style>
</head>

<body>
<p class="typewriter">这是一个打字机效果的文本</p>
</body>
</html>

在上述代码中,.typewriter 类的元素用于实现打字机效果。

animation: typing 4s steps(30), blink 0.5s step-end infinite; 定义了两个动画:

  • typing 动画用于模拟文字逐个出现的效果,从宽度为 0 逐渐增加到 300pxsteps(30) 表示分 30 步完成动画,使文字出现有逐个显示的效果。

  • blink 动画用于模拟光标闪烁效果,每 0.5s 闪烁一次,在 50% 进度时,光标(通过右边框实现)变为透明来模拟闪烁。

css 实现翻牌效果

主要是考察几个属性的使用

  • transform: rotateY 用于 Y 轴旋转
  • transition 用于过度动画

还有一个要点:

  • 翻转卡牌的时候,正面在上, 要将背面隐藏; 背面在上, 要将正面隐藏;

效果如下: 01.gif

实现比较简单, 直接贴代码

<!DOCTYPE html>
<html lang="en">
<head>
<style>
.card {
display: flex;
}

.flip-card {
float: left;
position: relative;
height: 36vmin;
width: calc(40vmin / 1.4);
background-color: white;
padding: 20px;
border-radius: calc(40vmin / 20);
box-shadow: 0 calc(40vmin / 40) calc(40vmin / 10) 0 rgba(0, 0, 0, 0.6);
overflow: hidden;
transition: transform 200ms linear, box-shadow 200ms linear, background-color 200ms linear;
transform: rotateY(0deg);
}

.label:hover .flip-card {
transform: rotateY(180deg);
background-color: black;
transition: transform 200ms linear, box-shadow 200ms linear, background-color 200ms linear;
}

.label:hover .flip-front {
opacity: 0;
display: none;
transition: transform 200ms linear, box-shadow 200ms linear, background-color 200ms linear;
}

.label:hover .flip-end {
opacity: 1;
display: block;
transform: rotateY(180deg);
color: white;
font-size: 20px;
transition: transform 200ms linear, box-shadow 200ms linear, background-color 200ms linear;
}

.flip-front {
width: 100%;
height: 100%;
opacity: 1;
cursor: pointer;
}

.flip-end {
width: 100%;
height: 100%;
opacity: 0;
display: none;
cursor: pointer;
}

.label {
background-color: white;
border-radius: calc(40vmin / 20);
}
</style>
</head>
<body>
<div class="card">
<div class="label">
<div class="flip-card">
<div class="flip-front">我是正面</div>
<div class="flip-end">
在上述代码中,我们创建了一个带有 card 类的容器,内部有一个 card-inner 元素,它包含了 card-front(正面)和
card-back(背面)两个元素。 当鼠标悬停在 card 元素上时,通过 :hover 选择器将 card-inner 元素绕 Y 轴旋转 180
度,实现翻牌效果。
</div>
</div>
</div>
</div>
</body>
</html>

全局样式命名冲突和样式覆盖问题怎么解决?

在前端开发过程中,有几种常见的方法可以解决全局样式命名冲突和样式覆盖问题:

  1. 使用命名空间(Namespacing):给样式类名添加前缀或命名空间,以确保每个组件的样式类名不会冲突。例如,在一个项目中,可以为每个组件的样式类名都添加一个唯一的前缀,例如.componentA-button.componentB-button,这样可以避免命名冲突。

  2. 使用BEM命名规范:BEM(块、元素、修饰符)是一种常用的命名规范,可以将样式类名分成块(block)、元素(element)和修饰符(modifier)三个部分,以确保样式的唯一性和可读性。例如,.button表示一个块,.button__icon表示一个元素,.button--disabled表示一个修饰符。

  3. 使用CSS预处理器:CSS预处理器(如Sass、Less)可以提供变量、嵌套规则和模块化等功能,可以更方便地管理样式并避免命名冲突。例如,可以使用变量来定义颜色和尺寸,使用嵌套规则来组织样式,并将样式拆分成多个模块。

  4. 使用CSS模块:CSS模块提供了在组件级别上限定样式作用域的能力,从而避免了全局样式的冲突和覆盖。每个组件的样式定义在组件内部,使用唯一的类名,确保样式的隔离性和唯一性。

  5. 使用CSS-in-JS解决方案:CSS-in-JS是一种将CSS样式直接写入JavaScript代码中的方法,通过将样式与组件绑定,可以避免全局样式的冲突问题。一些常见的CSS-in-JS解决方案包括Styled Components、Emotion和CSS Modules with React等。

CSS 如何实现文本溢出?

单行文本溢出

在CSS中,可以使用text-overflow属性来实现单行文本的溢出省略样式。同时,还需要设置white-space属性为nowrap,使文本不换行,以及overflow属性为hidden,隐藏溢出的文本。

以下是一个示例:

.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

然后,在HTML中,可以将这个类应用到指定的元素上:

<p class="ellipsis">这是一段很长的文本,如果超过指定的宽度,就会显示省略号。</p>

这样,如果文本超过了指定的宽度,就会自动显示省略号。


多行文本溢出

CSS中没有直接的属性可以实现省略样式。但是,可以使用一些技巧来实现多行文本的省略样式。其中一种常用的方法是使用-webkit-line-clamp属性和-webkit-box-orient属性来限制显示的行数,并且设置display属性为-webkit-box以创建一个块级容器。

以下是一个示例:

.ellipsis-multiline {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3; // 设置显示的行数 */
overflow: hidden;
text-overflow: ellipsis;
}

然后,在HTML中,将这个类应用到指定的元素上:

<div class="ellipsis-multiline">
这是一个多行文本的示例,如果文本内容超过了指定的行数,就会显示省略号。这是一个多行文本的示例,如果文本内容超过了指定的行数,就会显示省略号。这是一个多行文本的示例,如果文本内容超过了指定的行数,就会显示省略号。
</div>

请注意,-webkit-line-clamp属性只在某些WebKit浏览器中(如Chrome和Safari)支持。在其他浏览器中,可能需要使用其他解决方案来实现多行文本的省略样式。

实现页面顶部, 自定义滚动进度条样式

要实现页面顶部的自定义滚动进度条样式,可以按照以下步骤进行:

  1. 在HTML中添加滚动进度条的容器元素,通常可以使用一个<div>元素作为容器,放在页面顶部的合适位置。
<div id="scroll-progress"></div>
  1. 在CSS中定义滚动进度条的样式。可以使用背景颜色、高度、透明度等属性来自定义样式。
#scroll-progress {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 5px;
background-color: #f00; // 自定义进度条颜色 */
opacity: 0.7; // 自定义进度条透明度 */
z-index: 9999; // 确保进度条显示在最顶层 */
}
  1. 使用JavaScript来监听页面滚动事件,并更新滚动进度条的宽度。
const scrollProgress = document.getElementById('scroll-progress')
let requestId

function updateScrollProgress () {
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight
const progress = (scrollTop / (scrollHeight - window.innerHeight)) * 100
scrollProgress.style.width = progress + '%'
requestId = null
}

function scrollHandler () {
if (!requestId) {
requestId = requestAnimationFrame(updateScrollProgress)
}
}

window.addEventListener('scroll', scrollHandler)

以上就是一个简单的实现页面顶部自定义滚动进度条样式的方法。根据自己的需求,可以调整CSS样式和JavaScript的逻辑来实现不同的效果。

完整代码:

<!DOCTYPE html>
<html>
<head>
<title>自定义滚动进度条样式</title>
<style>
#scroll-progress {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 5px;
background-color: #f00; // 自定义进度条颜色 */
opacity: 0.7; // 自定义进度条透明度 */
z-index: 9999; // 确保进度条显示在最顶层 */
}
</style>
</head>
<body>
<div id="scroll-progress"></div>

<!-- 假设有很长的内容 -->
<div style="height: 2000px;"></div>

<script>
var scrollProgress = document.getElementById('scroll-progress');
var requestId;

function updateScrollProgress() {
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
var scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
var progress = (scrollTop / (scrollHeight - window.innerHeight))100;
scrollProgress.style.width = progress + '%';
requestId = null;
}

function scrollHandler() {
if (!requestId) {
requestId = requestAnimationFrame(updateScrollProgress);
}
}

window.addEventListener('scroll', scrollHandler);
</script>
</body>
</html>

css 隐藏元素的方法有哪些

有多种方法可以隐藏元素的CSS。

  1. display: none;:将元素完全隐藏,不占据任何空间。
  2. visibility: hidden;:将元素隐藏,但仍占据空间。
  3. opacity: 0;:将元素透明化,但仍占据空间。
  4. position: absolute; left: -9999px;:将元素定位到屏幕外部,不显示在可见区域。
  5. height: 0; width: 0; overflow: hidden;:将元素高度和宽度设为0,同时隐藏溢出内容。
  6. clip-path: polygon(0 0, 0 0, 0 0);:使用剪切路径将元素隐藏。

这些方法可以根据具体的需求选择合适的方式来隐藏元素。使用 display: none; 是最常见和常用的隐藏元素的方法,它会完全移除元素并且不占据页面空间。而其他方法则可以根据需要在元素隐藏的同时保留占位空间或其他特殊效果。

display: none;visibility: hidden;opacity: 0; 区别是啥

display: none;visibility: hidden;opacity: 0; 是用于隐藏元素的CSS属性,它们之间有一些区别:

  1. display: none;:该属性会完全移除元素,并且不占据页面空间。隐藏后的元素在文档流中不可见,也不会影响其他元素的布局。相当于元素被完全移除了,无法通过任何方式找到它。当需要彻底从页面中移除元素时,可以使用该属性。

  2. visibility: hidden;:该属性会将元素隐藏,但仍然占据页面空间。隐藏后的元素在文档流中保留了位置,仅仅是不可见了。元素隐藏后不会影响其他元素的布局。可以通过JavaScript或其他方式找到该元素,并且可以在需要时将其重新显示。

  3. opacity: 0;:该属性将元素设置为完全透明。元素仍然占据页面空间,但是不可见。透明元素在文档流中保留位置,并且不会影响其他元素的布局。可以通过JavaScript或其他方式找到该元素,并在需要时将其重新设置为可见。

综上所述,display: none; 完全移除元素并且不占据空间,visibility: hidden; 保留元素位置但不可见,opacity: 0; 使元素透明但仍然占据空间。根据具体需求选择合适的属性来隐藏元素。

H5 如何解决移动端适配问题

移动端适配问题是指如何让网页在不同的移动设备上显示效果相同。下面是一些常见的 H5 移动端适配方案:

  1. 使用 viewport 标签

通过设置 viewport 标签的 meta 属性,来控制页面的缩放比例和宽度,以适配不同的设备。例如:

<meta name="viewport" content="width=device-width, initial-scale=1.0">

其中 width=device-width 表示设置 viewport 的宽度为设备宽度,initial-scale=1.0 表示初始缩放比例为 1。

  1. 使用 CSS3 的媒体查询

通过 CSS3 的媒体查询,根据不同的设备宽度设置不同的样式,以适配不同的设备。例如:

arduinoCopy code@media screen and (max-width: 640px) {
// 样式 */
}

其中 max-width 表示最大宽度,当屏幕宽度小于等于 640px 时,应用这些样式。

  1. 使用 rem 单位

通过将 px 转化为 rem 单位,根据不同的设备字体大小设置不同的样式,以适配不同的设备。例如:

html {
font-size: 16px;
}

@media screen and (max-width: 640px) {
html {
font-size: 14px;
}
}

<div {
width: 10rem;
}

其中 font-size: 16px 表示将网页的基准字体大小设置为 16px,font-size: 14px 表示在屏幕宽度小于等于 640px 时将基准字体大小设置为 14px,div 元素的 width: 10rem 表示该元素的宽度为 10 个基准字体大小。

  1. 使用 flexible 布局方案

通过使用 flexible 布局方案,将 px 转化为 rem 单位,并且动态计算根节点的字体大小,以适配不同的设备。例如使用 lib-flexible 库:

arduinoCopy code// index.html
<script src="https://cdn.bootcdn.net/ajax/libs/lib-flexible/0.3.4/flexible.js"></script>

// index.js
import 'lib-flexible/flexible.js'

其中 flexible.js 会在页面加载时动态计算根节点的字体大小,并将 px 转化为 rem 单位。在样式中可以直接使用 px 单位,例如:

<div {
width: 100px;
height: 100px;
}

这个 div 元素的大小会根据设备屏幕的宽度进行适配。

可以通过根据请求来源(User-Agent)来判断访问设备的类型,然后在服务器端进行适配。例如,可以在服务器端使用 Node.js 的 Express 框架,在路由中对不同的 User-Agent 进行判断,返回不同的页面或数据。具体实现可以参考以下步骤:

  1. 根据 User-Agent 判断访问设备的类型,例如判断是否为移动设备。可以使用第三方库如 ua-parser-js 进行 User-Agent 的解析。

  2. 如果是移动设备,可以返回一个 H5 页面或接口数据。

  3. 如果是 PC 设备,可以返回一个 web 应用页面或接口数据。

具体实现方式还取决于应用的具体场景和需求,以上只是一个大致的思路。

实现 table header 吸顶, 有哪些实现方式?

实现 table header 吸顶的方法有多种,以下是一些基于 CSS 的实现方式:

  1. 使用 position: sticky 属性:在表格头部的 CSS 中,使用 position: sticky 属性可以使表格头部保持在视窗的顶部或底部,而不会随着滚动而消失。例如:
cssCopy codeth {
position: sticky;
top: 0;
background-color: #fff;
}
  1. 使用 CSS transform 属性:在表格头部的 CSS 中,使用 CSS transform 属性可以使表格头部保持固定位置,而不会随着滚动而消失。例如:
cssCopy codeth {
position: relative;
z-index: 1;
}
thead {
position: fixed;
top: 0;
visibility: hidden;
z-index: 2;
transform: translateY(0);
}
tbody {
margin-top: 50px;
}
  1. 使用 JavaScript 和 CSS:使用 JavaScript 和 CSS 可以使表格头部保持在视窗的顶部或底部,而不会随着滚动而消失。例如:
htmlCopy code<div class="table-wrapper">
<table>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>Row 1, Column 1</td>
<td>Row 1, Column 2</td>
<td>Row 1, Column 3</td>
</tr>
<tr>
<td>Row 2, Column 1</td>
<td>Row 2, Column 2</td>
<td>Row 2, Column 3</td>
</tr>
...
</tbody>
</table>
</div>
<script>
window.onscroll = function() {
var header = document.querySelector(".table-wrapper thead");
if (window.pageYOffset > 150) {
header.classList.add("sticky");
} else {
header.classList.remove("sticky");
}
};
</script>
<style>
.table-wrapper {
position: relative;
}
.table-wrapper thead {
position: fixed;
top: 0;
z-index: 1;
background-color: #fff;
}
.table-wrapper th {
height: 50px;
}
.table-wrapper.sticky thead {
position: absolute;
top: 50px;
}
</style>

通过以上方法的一些组合使用,可以实现 table header 吸顶,提升表格的用户体验和易用性。

实现 table header 吸顶的方法有多种,以下是一些基于 CSS 的实现方式:

  1. 使用 position: sticky 属性:在表格头部的 CSS 中,使用 position: sticky 属性可以使表格头部保持在视窗的顶部或底部,而不会随着滚动而消失。例如:
cssCopy codeth {
position: sticky;
top: 0;
background-color: #fff;
}
  1. 使用 CSS transform 属性:在表格头部的 CSS 中,使用 CSS transform 属性可以使表格头部保持固定位置,而不会随着滚动而消失。例如:
cssCopy codeth {
position: relative;
z-index: 1;
}
thead {
position: fixed;
top: 0;
visibility: hidden;
z-index: 2;
transform: translateY(0);
}
tbody {
margin-top: 50px;
}
  1. 使用 JavaScript 和 CSS:使用 JavaScript 和 CSS 可以使表格头部保持在视窗的顶部或底部,而不会随着滚动而消失。例如:
htmlCopy code<div class="table-wrapper">
<table>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>Row 1, Column 1</td>
<td>Row 1, Column 2</td>
<td>Row 1, Column 3</td>
</tr>
<tr>
<td>Row 2, Column 1</td>
<td>Row 2, Column 2</td>
<td>Row 2, Column 3</td>
</tr>
...
</tbody>
</table>
</div>
<script>
window.onscroll = function() {
var header = document.querySelector(".table-wrapper thead");
if (window.pageYOffset > 150) {
header.classList.add("sticky");
} else {
header.classList.remove("sticky");
}
};
</script>
<style>
.table-wrapper {
position: relative;
}
.table-wrapper thead {
position: fixed;
top: 0;
z-index: 1;
background-color: #fff;
}
.table-wrapper th {
height: 50px;
}
.table-wrapper.sticky thead {
position: absolute;
top: 50px;
}
</style>

通过以上方法的一些组合使用,可以实现 table header 吸顶,提升表格的用户体验和易用性。

CSS 文档流 是什么概念?

答案

核心概念

CSS 的文档流(Document Flow)是指文档中元素按照其在 HTML 中出现的顺序自上而下布局的方式,也称为常规流(Normal Flow)或默认流。文档流定义了元素的布局顺序和定位方式,包括元素的位置、大小、间距等属性。

文档流特性

在文档流中,每个元素都会占据一定的空间并尽可能充满其包含块的宽度。每个元素的位置都会受到前面元素的影响,如果前面的元素发生位置变化,那么后面的元素的位置也会发生相应的变化。

元素排列规则

文档流中的元素按照下面的规则排列:

  1. 块级元素:块级元素会独占一行,并在前面自动添加一个垂直间距。例如:<p><div><h1> 等。

  2. 行内元素:行内元素会在一行中排列,并且宽度根据内容自适应。例如:<a><span><img> 等。

  3. 行内块级元素:行内块级元素与行内元素类似,但是它可以设置宽度、高度等块级元素的属性。例如:<input><button><textarea> 等。

实际应用

文档流是 CSS 中最基本、最重要的概念之一,它决定了网页的整体布局和排版方式,也是实现网页布局的基础。在实际开发中,我们需要理解文档流的特性和工作原理,以便更好地掌握网页布局和样式的设计。

面试官视角

该题考察对 CSS 基础概念的理解,是前端开发中的核心知识点。面试官通过此题可以了解候选人对页面布局原理的掌握程度。

延伸阅读

CSS 中 position 常见属性有哪些,大概讲一下?

答案

核心概念

CSS 中 position 属性用于指定元素的定位方式,它决定了元素在页面中的定位策略和布局行为。

常见属性值

  1. static:默认值,元素在文档流中正常排列。

  2. relative:元素在文档流中正常排列,但是可以通过设置 toprightbottomleft 属性相对于其正常位置进行偏移,不会影响其它元素的位置。

  3. absolute:元素脱离文档流,相对于最近的非 static 定位的祖先元素进行定位,如果没有则相对于 <html> 元素进行定位。通过设置 toprightbottomleft 属性进行偏移,如果祖先元素发生位置变化,则元素的位置也会发生相应的变化。

  4. fixed:元素脱离文档流,相对于浏览器窗口进行定位,始终保持在窗口的固定位置,不会随页面滚动而滚动。通过设置 toprightbottomleft 属性进行偏移。

  5. sticky:元素在文档流中正常排列,当元素滚动到指定的位置时,停止滚动并固定在该位置,直到其祖先元素发生滚动时才会取消固定。通过设置 toprightbottomleft 属性和 z-index 属性进行设置。

实际应用

以上是 position 属性的常见属性值和简单说明,不同的值会对元素进行不同的定位方式,开发人员可以根据需要选择合适的值来实现页面布局。

面试官视角

该题考察对 CSS 定位系统的理解,是前端开发中的基础知识点。面试官通过此题可以了解候选人对页面布局和定位技术的掌握程度。

延伸阅读

未知高度和宽度元素的水平垂直居中的方案有哪些, 简单手写一下?

答案

核心概念

未知高度和宽度元素的水平垂直居中是 CSS 布局中的常见需求,有多种实现方案,每种方案都有其适用场景。

实现方案

  1. 当要被居中的元素是 inline 或者 inline-block 元素
#container {
display: table-cell;
text-align: center;
vertical-align: middle;
}

#center {
/* 元素内容 */
}
  1. 利用 CSS3 的 transform,可以轻松的在未知元素的高宽的情况下实现元素的垂直居中
#container {
position: relative;
}
#center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
  1. Flexbox 方案
#container {
display: flex;
justify-content: center;
align-items: center;
}

#center {
/* 元素内容 */
}
  1. Grid 方案
#container {
display: grid;
place-items: center;
}

#center {
/* 元素内容 */
}

方案对比

方案兼容性适用场景优点缺点
table-cell很好简单居中兼容性好语义化差
transform绝对定位居中精确控制需要定位
flexbox现代布局灵活强大需要容器
grid一般现代布局简洁兼容性一般

面试官视角

该题考察对 CSS 布局技术的掌握程度,体现了候选人对不同布局方案的理解和选择能力。

延伸阅读

55%