<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ CSS - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ freeCodeCamp 是一个免费学习编程的开发者社区，涵盖 Python、HTML、CSS、React、Vue、BootStrap、JSON 教程等，还有活跃的技术论坛和丰富的社区活动，在你学习编程和找工作时为你提供建议和帮助。 ]]>
        </description>
        <link>https://www.freecodecamp.org/chinese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ CSS - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/chinese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 14 May 2026 14:35:04 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/chinese/news/tag/css/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ 如何使用 CSS 使文本垂直居中 ]]>
                </title>
                <description>
                    <![CDATA[ 如果你在 div 中包含一些文本，而没有其他内容，那么 div 的高度将与文本的高度相匹配。但是，假设你有一些文本和一张图片，文本将在 div  的底部对齐，这通常不是你想要的。 在本文中，你将学习几种将文字在 div 或其他元素中垂直居中的方法。 如何使用 Line Height 使文本居中 这种方法有一定的局限性，但如果你使用 height 属性将元素设置为固定高度，这种方法还是很有用的。 line-height 属性决定浏览器渲染文本时方框的高度。默认情况下，该值被设置为略大于 1，以实现合适的文本行间距。 如果将元素的 height 和 line-height 设置为相同值，文本将垂直居中： .my-element {   height: 3rem;   line-height: 3rem; } 使用 line-height 垂直居中文本 不过，使用这种方法有一个重要的注意事项。只有当文本可以在一行中显示时，这种方法才有效。 如果文本确实换行了，你会看到第一行垂直居中。因为你设置的 line-height 与元素的 height 相同，所以换行的文本行现在会溢 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/how-to-center-text-vertically-with-css/</link>
                <guid isPermaLink="false">66de6bf8bfce610438ed5f44</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Miya Liu ]]>
                </dc:creator>
                <pubDate>Mon, 09 Sep 2024 10:19:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2024/09/pexels-alexander-ermakov-12154194.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/how-to-center-text-vertically-with-css/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Center Text Vertically with CSS</a>
      </p><p>如果你在 <code>div</code> 中包含一些文本，而没有其他内容，那么 <code>div</code> 的高度将与文本的高度相匹配。但是，假设你有一些文本和一张图片，文本将在 <code>div</code> 的底部对齐，这通常不是你想要的。</p><p>在本文中，你将学习几种将文字在 <code>div</code> 或其他元素中垂直居中的方法。</p><h2 id="-line-height-">如何使用 Line Height 使文本居中</h2><p>这种方法有一定的局限性，但如果你使用 <code>height</code> 属性将元素设置为固定高度，这种方法还是很有用的。</p><p><code>line-height</code> 属性决定浏览器渲染文本时方框的高度。默认情况下，该值被设置为略大于 1，以实现合适的文本行间距。</p><p>如果将元素的 <code>height</code> 和 <code>line-height</code> 设置为相同值，文本将垂直居中：</p><pre><code class="language-css">.my-element {
  height: 3rem;
  line-height: 3rem;
}
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/10/image-91.png" class="kg-image" alt="Image" width="600" height="400" loading="lazy"></figure><p><em><em><em><em>使用</em></em></em> <em><em><em>line-height</em></em></em> 垂直居中文本</em></p><p>不过，使用这种方法有一个重要的注意事项。只有当文本可以在一行中显示时，这种方法才有效。</p><p>如果文本确实换行了，你会看到第一行垂直居中。因为你设置的 <code>line-height</code> 与元素的 <code>height</code> 相同，所以换行的文本行现在会溢出元素。</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/10/image-94.png" class="kg-image" alt="Image" width="600" height="400" loading="lazy"></figure><p><em><em><em><em>换行的</em></em></em>文本溢出容器</em></p><p>如果这听起来太死板，请继续往下看。接下来，你将看到如何使用 Flexbox 将文本和元素内的其他内容垂直居中。</p><h2 id="-flexbox-">如何使用 Flexbox 将文本居中</h2><p>更好、更通用的解决方案是使用 flexbox 布局，并将对齐项设置为居中。</p><p>使用 Flexbox（flex 容器）的元素可以按行或列布局元素（flex 项）。Flexbox 布局有两条假想线贯穿其中。第一条是主轴，项目将沿着它放置。对于 flexbox <code>row</code>，主轴是水平轴。</p><p>横轴垂直于主轴。你可以使用横轴来定义 flex 容器内元素的垂直对齐方式。</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/10/image-92.png" class="kg-image" alt="Image" width="600" height="400" loading="lazy"></figure><p><em>水平 flexbox 布局中的主轴和横轴</em></p><p>以下是应用 flexbox 布局并将文本垂直居中所需的 CSS：</p><pre><code class="language-css">.my-element {
    /* Use a flexbox layout */
    display: flex;

    /* Make a horizontal flexbox (the default) */
    flex-direction: row;

    /* The important part: vertically center the items */
    align-items: center;
}
</code></pre><p>这将创建一个水平的 flexbox 布局（<code>flex-direction: row</code> 并非严格要求，因为它是默认设置）。<code>align-items</code> 属性决定了项目沿横轴或纵轴的对齐方式。有几种不同的值可以使用，这里可以使用 <code>center</code> 将文本垂直居中。</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/10/image-96.png" class="kg-image" alt="Image" width="600" height="400" loading="lazy"></figure><p><em><em><em><em>使用 align-items: center</em></em></em> 对齐文本</em></p><p>这样做效果很好，甚至可以处理多行文本。如果元素内有其他内容，如图片，所有内容都将垂直对齐。</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/10/image-95.png" class="kg-image" alt="Image" width="600" height="400" loading="lazy"></figure><p><em>文本与其他内容垂直对齐</em></p><h2 id="-css-grid-">如何使用 CSS Grid 使文本居中</h2><p>你也可以使用 CSS grid 将内容垂直居中。</p><p>对于包含要居中的文本的单个 <code>div</code>，你可以将其转化为一行一列的网格布局。</p><pre><code class="language-css">.my-element {
    display: grid;
    align-items: center;
}
</code></pre><p>在网格布局中，<code>align-items</code> 属性指定了单元格内内容沿列（垂直）轴的对齐方式。这将垂直对齐 <code>div</code> 元素中的文本。</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/10/image-98.png" class="kg-image" alt="Image" width="600" height="400" loading="lazy"></figure><p><em>使用 1x1 网格布局使文本垂直居中</em></p><p>如果包含文本的元素已经是网格布局的一部分，可以将 <code>align-items: center</code> 应用于整个网格，或者如果只想控制一个网格单元格的垂直对齐方式，可以使用 <code>align-self: center</code>。</p><h2 id="-"><strong>总结</strong></h2><p>现在你知道如何将文本垂直居中了吧。下次再看到关于将 <code>div</code> 居中的推文时，你就可以用新学到的 CSS 知识回复了！</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 媒体查询与容器查询——该使用哪个以及何时使用？ ]]>
                </title>
                <description>
                    <![CDATA[ 随着 Web 的发展，不断有新工具和新理念问世，旨在让我们的 Web 开发工作变得更加轻松。这意味着我们必须选择是坚持旧的方法还是完全弃用它们转而使用新工具。但这是否总需要一种非此即彼的解决方案呢？ 在这种情况下，理想的做法是了解两种概念——比较它们的优缺点，然后决定它们最合适的应用场景。本文将对 CSS 媒体查询和容器查询做这样的探讨。 目录  * 响应式和内在网页设计  * 什么是媒体查询  * 什么是容器查询  * 媒体查询和容器查询比较  * 什么时候应该使用哪个  * 总结 响应式和内在网页设计 在 2010 年以前，Web 开发人员可以轻松创建主要在桌面上运行的网站。这种情况直到 Ethan Marcotte 提出了响应式 Web 设计（RWD）的概念才有所改变。根据 MDN 的定义 [https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Responsive_Design] ，响应式 Web 设计是一种面向多设备 Web 设计方式。这促使了媒体查询作为 RWD 的一个组成部分被采用。 但最近出现 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/media-queries-vs-container-queries/</link>
                <guid isPermaLink="false">6691eb81dd1680043183e219</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Miya Liu ]]>
                </dc:creator>
                <pubDate>Wed, 17 Jul 2024 04:02:14 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2024/07/titleimage.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/media-queries-vs-container-queries/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Media Queries vs Container Queries – Which Should You Use and When?</a>
      </p><!--kg-card-begin: markdown--><p>随着 Web 的发展，不断有新工具和新理念问世，旨在让我们的 Web 开发工作变得更加轻松。这意味着我们必须选择是坚持旧的方法还是完全弃用它们转而使用新工具。但这是否总需要一种非此即彼的解决方案呢？</p>
<p>在这种情况下，理想的做法是了解两种概念——比较它们的优缺点，然后决定它们最合适的应用场景。本文将对 CSS 媒体查询和容器查询做这样的探讨。</p>
<h2 id="">目录</h2>
<ul>
<li><a href="#responsive-and-intrinsic-web-design">响应式和内在网页设计</a></li>
<li><a href="#what-are-media-queries">什么是媒体查询</a></li>
<li><a href="#what-are-container-queries">什么是容器查询</a></li>
<li><a href="#how-do-media-queries-and-container-queries-compare">媒体查询和容器查询比较</a></li>
<li><a href="#which-should-you-use-and-when">什么时候应该使用哪个</a></li>
<li><a href="#conclusion">总结</a></li>
</ul>
<h2 id="responsive-and-intrinsic-web-design">响应式和内在网页设计</h2>
<p>在 2010 年以前，Web 开发人员可以轻松创建主要在桌面上运行的网站。这种情况直到 Ethan Marcotte 提出了响应式 Web 设计（RWD）的概念才有所改变。根据 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Responsive_Design">MDN 的定义</a>，响应式 Web 设计是一种面向多设备 Web 设计方式。这促使了媒体查询作为 RWD 的一个组成部分被采用。</p>
<p>但最近出现了一种趋势，即 Jen Simmons 定义的内在网页设计——创建上下文感知组件的需求。容器查询正是实现这一目标的工具。</p>
<h2 id="what-are-media-queries">什么是媒体查询</h2>
<p>媒体查询是一种基于满足特定条件来应用指定样式的规则。它们通常用于确保网站在各种设备上具有响应性，通过查询视口宽度来实现。</p>
<p>媒体查询的特点是一个 @media 规则，后跟一个括号中的条件及大括号内的表达式，如果满足条件则将应用该表达式。因此，如果我们想根据设备的视口宽度更改 div 的背景色，可以这样操作：</p>
<pre><code class="language-css">/* 移动设备 */
@media (max-width: 480px) {
  .mysite {
    background-color: red;
  }
}
</code></pre>
<p>在上述示例中，我们要求当视口宽度达到最大 480px 时，将类名为 mysite 的 <code>&lt;div&gt;</code> 的背景色设置为红色。</p>
<p><strong>提示</strong>：max-width 用于假设一个桌面优先的设计，并在向下调整时定位更小的设备。如果是移动优先的设计，我们会使用 min-width 来定位更大的屏幕。</p>
<h2 id="what-are-container-queries">什么是容器查询</h2>
<p>容器查询是一种基于父容器的大小来应用指定样式的规则。它们为 Web 开发者们长期以来希望能响应页面内个别容器变化的需求提供了解决方案，而不仅仅是整个视口的变化。</p>
<pre><code class="language-css">.header {
   container: mysite / inline-size;
}

@container mysite (min-width: 600px) {
   .maincard {
	   grid-template-column: 1fr 1fr;
    }
   .item {
       background-color: green;
    }
}
</code></pre>
<p>如上代码所示，我们首先定义了一个容器，我们希望对其子元素做出改变。在我们的例子中，我们希望对 header 容器内的 class 为 item 的元素进行更改。你可以通过给容器命名（可选）和指定类型来做到这一点。</p>
<p>接下来，使用 @container 规则，我们检查条件并在满足条件时应用一些样式。对于最小宽度 600px，我们希望背景色为绿色并设置两个网格列。</p>
<p><strong>提示</strong>：你不直接定义一个容器以对该容器本身进行更改，而是对其子元素进行更改。这意味着如果我们想对 header 容器本身进行更改，我们必须将它嵌套在另一个容器中，例如容器 A，并查询 A 以影响其子元素——header。</p>
<h2 id="how-do-media-queries-and-container-queries-compare">媒体查询和容器查询比较</h2>
<p>现在，我们了解了两者的工作原理，让我们看看它们在实际中的表现。下面的 CodePen 示例展示了一个四个元素的布局。前两个使用容器查询设置样式，而后两个使用媒体查询设置样式。你可以调整视口大小，查看元素如何响应。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/mqvscq-demo.png" alt="mqvscq-demo" width="600" height="400" loading="lazy"></p>
<p>媒体查询和容器查询 CodePen 示例：项目灵感来自 Miriam Suzanne。</p>
<p>参见 CodePen 上 Ophy Boamah (<a href="https://codepen.io/ophyboamah">@ophyboamah</a>) 的 <a href="https://codepen.io/ophyboamah/pen/YzbaROw">MQ vs CQ (来源 MS)</a>。</p>
<h3 id="">媒体查询和容器查询的主要区别</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/comparetable.png" alt="comparetable" width="600" height="400" loading="lazy"></p>
<h3 id="vs">基于视口 vs. 基于容器</h3>
<p>媒体查询基于视口（整个浏览器窗口）的大小应用样式。这意味着布局根据整体屏幕大小进行调整，使其适合在不同设备（如手机、平板电脑和桌面）上进行设计调整。</p>
<p>而容器查询基于包含它们的容器元素的大小应用样式。这使得单个组件可以根据自身大小，而不是视口大小来调整其外观，使它们在网页的不同部分中具有高度的灵活性和可重用性。</p>
<h3 id="">模块化和灵活性</h3>
<p>由于媒体查询依赖于视口大小，它们在创建真正模块化的组件时可能不太有效。调整页面某个部分的样式可能会无意中影响其他部分，尤其是在复杂的布局中。此外，在组件需要在较大布局中独立适应的情况下，它们可能会显得不足。这会导致 CSS 变得难以维护。</p>
<p>相比之下，容器查询通过允许基于容器大小定义样式来促进模块化和灵活性。这意味着你可以创建自包含、可适应的组件，并且可以在网站的不同部分重复使用而不会导致意外变化，从而增强了它们的可重用性。</p>
<p>这使得设计更加自适应，组件可以调整自己的布局和外观，这在现代、基于组件的设计系统中非常有用。</p>
<h3 id="">复杂性和维护</h3>
<p>在大型项目中，管理大量媒体查询会变得很麻烦。随着断点和特殊情况的增加，CSS 会变得复杂且难以维护。随着时间的推移，这可能会导致代码库膨胀且管理起来困难。</p>
<p>容器查询可以简化大型项目中 CSS 的维护。通过保持样式遵从组件和上下文，CSS 变得更加有序和模块化。这减少了管理全局断点的复杂性，使其更易于维护，从而生成一个更有组织的代码库。</p>
<h2 id="which-should-you-use-and-when">你应该使用哪个以及什么时候使用</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/finalsection.png" alt="finalsection" width="600" height="400" loading="lazy"></p>
<p>媒体查询 vs 容器查询（图片来源：<em><a href="http://web.dev/">web.dev</a></em>）</p>
<p>我们在前几节讨论的内容旨在帮助你做出明智的决定。在了解了这两个概念的比较和对比之后，现在考虑以下因素：</p>
<h3 id="">理解和舒适度</h3>
<p>你对每个概念的理解如何？容器查询相对较新，但如果你花时间学习和实验，就像媒体查询一样，其学习曲线并不令人望而生畏。所以在生产中使用你理解并且更熟悉的那个，会让你的生活更轻松。</p>
<h3 id="">项目需求和复杂性</h3>
<p>你正在使用的设计方法是什么，你的项目有多复杂？因为有时候你项目的设计方法会决定哪一种最适合你的需求。而且，项目越复杂，维护代码就越难，你需要使用那些你可以管理的。</p>
<h3 id="">未来趋势和协作</h3>
<p>响应式设计的未来看起来越来越内在化。我们正在逐渐转向基于组件内容的响应性变化，容器查询在这里表现最佳。</p>
<p>但媒体查询似乎在短时间内不会消失，所以你可以一起使用它们，以实现跨多个设备的完美响应。</p>
<h2 id="conclusion">总结</h2>
<p>容器查询允许在 CSS 中创建可重用组件的潜力令人兴奋——但它可能还没有准备好完全取代媒体查询。</p>
<p>目前，我们最好的选择是一起使用它们，并根据实际情况来选择其中一个。通过进一步实验以了解两种方法各自的优缺点，可以确保做出正确的决定。</p>
<p>这里有一些有用的资源：</p>
<ul>
<li><a href="https://www.freecodecamp.org/news/learn-css-media-queries-by-building-projects/">freeCodeCamp 专栏文章：通过创建 3 个项目学习 CSS 媒体查询</a></li>
<li><a href="https://ishadeed.com/article/css-container-query-guide/">Ahmad Shadeed 关于容器查询的文章</a></li>
<li><a href="https://www.youtube.com/watch?v=2rlWBZ17Wes">视频：如何使用媒体查询和容器查询</a></li>
</ul>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ CSS 过渡与动画手册——如何用 CSS 为元素制作动画 ]]>
                </title>
                <description>
                    <![CDATA[ CSS 过渡（Transition）和动画（Animation）为更改元素的样式提供了平滑、渐进的方式，但是它们的工作方式有些不同。 这是它们之间的主要区别： CSS 过渡 CSS 动画  * 创建一个从一个 CSS 值到另一个值平滑的过渡。   * 你需要触发器去运行 CSS 过渡。例如，你可以使用 `:hover` 伪类    [https://codesweetly.com/css-pseudo-selectors] 在用户指针悬停在元素上时运行过渡。   * 过渡只有两个状态：初始态和最终态。你不能创建中间步骤。   * 只运行一次。  * 最适合用在基础样式的更改。  * 从一个 CSS 关键帧到另一个关键帧的样式变更动画。   * CSS 动画不需要触发器。  * 动画允许你创建多种状态。  ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/css-transition-vs-css-animation-handbook/</link>
                <guid isPermaLink="false">6674044f5c4dc803d18ad2e7</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Mingxun Liu ]]>
                </dc:creator>
                <pubDate>Thu, 20 Jun 2024 10:31:22 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2024/06/How-to-Animate-Elements-in-CSS-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/css-transition-vs-css-animation-handbook/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">CSS Transition vs Animation Handbook – How to Animate Elements in CSS</a>
      </p><!--kg-card-begin: markdown--><p>CSS 过渡（Transition）和动画（Animation）为更改元素的样式提供了平滑、渐进的方式，但是它们的工作方式有些不同。</p>
<p>这是它们之间的主要区别：</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><table>
    <thead>
        <tr>
            <th>CSS 过渡</th>
            <th>CSS 动画</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>
                <ul>
                    <li>
                        创建一个从一个 CSS 值到另一个值平滑的过渡。
                    </li>
                    <li>
                        你需要触发器去运行 CSS 过渡。例如，你可以使用 `:hover` <a href="https://codesweetly.com/css-pseudo-selectors">伪类</a> 在用户指针悬停在元素上时运行过渡。
                    </li>
                    <li>
                        过渡只有两个状态：初始态和最终态。你不能创建中间步骤。
                    </li>
                    <li>只运行一次。</li>
                    <li>最适合用在基础样式的更改。</li>
                </ul>
            </td>
            <td>
                <ul>
                    <li>
                        从一个 CSS 关键帧到另一个关键帧的样式变更动画。
                    </li>
                    <li>CSS 动画不需要触发器。</li>
                    <li>动画允许你创建多种状态。</li>
                    <li>
                        你可以运行多次动画迭代——甚至是无数次。
                    </li>
                    <li>最适合使用在动态样式的更改。</li>
                </ul>
            </td>
        </tr>
    </tbody>
</table><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>本手册通过一些例子去解释两种动画技术，以便你理解它们之间的异同。</p>
<h2 id="">目录</h2>
<ol>
<li><a href="#what-are-css-transitions">什么是 CSS 过渡？</a></li>
<li><a href="#categories-of-css-transition-properties">CSS 过渡属性的种类</a>
<ul>
<li><a href="#what-are-the-required-css-transition-properties">什么是必需 CSS 过渡属性？</a></li>
<li><a href="#what-is-the-css-transition-property">什么是 <code>transition-property</code>？</a></li>
<li><a href="#what-is-the-css-transition-duration-property">什么是 <code>transition-duration</code>？</a></li>
<li><a href="#examples-of-the-required-css-transition-properties">必需 CSS 过渡属性的示例</a></li>
<li><a href="#what-are-the-optional-css-transition-properties">什么是可选 CSS 过渡属性？</a></li>
<li><a href="#what-is-the-css-transition-timing-function-property">什么是 <code>transition-timing-function</code>？</a></li>
<li><a href="#what-is-a-css-transition-delay-property">什么是 <code>transition-delay</code>？</a></li>
<li><a href="#examples-of-the-optional-css-transition-properties">可选 CSS 过渡属性的示例</a></li>
</ul>
</li>
<li><a href="#shorthand-for-defining-the-css-transition-properties">CSS 过渡属性的缩写</a></li>
<li><a href="#what-is-css-animation">什么是 CSS 动画？</a>
<ul>
<li><a href="#components-of-css-animations">CSS 动画的组成</a></li>
<li><a href="#what-are-css-keyframes">什么是 CSS <code>@keyframes</code></a></li>
</ul>
</li>
<li><a href="#what-are-css-animation-properties">什么是 CSS animation 属性？</a>
<ul>
<li><a href="#what-is-the-css-animation-name-property">什么是 CSS <code>animation-name</code> 属性？</a></li>
<li><a href="#what-is-the-css-animation-duration-property">什么是 CSS <code>animation-duration</code> 属性？</a></li>
<li><a href="#what-is-the-css-animation-timing-function-property">什么是 CSS <code>animation-timing-function</code> 属性？</a></li>
<li><a href="#what-is-the-css-animation-delay-property">什么是 CSS <code>animation-delay</code> 属性？</a></li>
<li><a href="#what-is-the-css-animation-iteration-count-property">什么是 CSS <code>animation-iteration-count</code> 属性？</a></li>
<li><a href="#what-is-the-css-animation-direction-property">什么是 CSS <code>animation-direction</code> 属性？</a></li>
<li><a href="#what-is-the-css-animation-play-state-property">什么是 CSS <code>animation-play-state</code> 属性？</a></li>
<li><a href="#what-is-the-css-animation-fill-mode-property">什么是 CSS <code>animation-fill-mode</code> 属性？</a></li>
</ul>
</li>
<li><a href="#what-is-a-css-animation-property">什么是 CSS <code>animation</code> 属性？</a></li>
<li><a href="#important-stuff-to-know-about-css-transitions-and-animations">CSS 过渡和动画的重要知识要点</a></li>
<li><a href="#wrapping-up">总结</a></li>
</ol>
<p>话不多说，我们讨论一下 CSS 过渡。</p>
<h2 id="what-are-css-transitions">什么是 CSS 过渡？</h2>
<p><strong>CSS 过渡</strong>提供了一种平滑、渐进的方式去更改指定的 CSS 属性值。</p>
<p>这样，CSS 过渡会使变化在指定时间段内平滑地发生，而不是让浏览器去立即更改某个属性值。</p>
<p>例如，假设你希望当悬停时更改一个元素的尺寸。在这个例子中，你有两个选项：</p>
<ol>
<li>不使用 CSS 过渡实现更改。</li>
<li>使用 CSS 过渡从元素的初始尺寸平滑地过渡到它的新状态。</li>
</ol>
<p>让我们看些这两个选项的例子。</p>
<h3 id="css">不使用 CSS 过渡如何在鼠标悬停时更改图片的尺寸</h3>
<pre><code class="language-css">img {
  width: 40%;
}

img:hover {
  width: 100%;
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-transitions/js-dsymqf"><strong>试着编辑它</strong></a></p>
<p>因为我们没有使用 CSS 过渡，上面的代码立即将图片的尺寸从初始宽度（<code>40%</code>）更改为新的宽度（<code>100%</code>）。</p>
<p>使用 CSS 过渡，你可以获得更愉悦的体验。让我们看看下面的示例。</p>
<h3 id="css">使用 CSS 过渡如何在鼠标悬停时更改图片的尺寸</h3>
<pre><code class="language-css">img {
  width: 40%;
  transition: width 3s ease-out 0.4s;
}

img:hover {
  width: 100%;
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-transitions/js-ufwgbu"><strong>试着编辑它</strong></a></p>
<p>从 <code>width: 40%</code> 到 <code>width: 100%</code>，<code>transition</code> 属性在图片上应用了一个平滑、渐进的过渡。</p>
<h2 id="categories-of-css-transition-properties">CSS 过渡属性的种类</h2>
<p>我们有两种 CSS 过渡属性：</p>
<ul>
<li><em>必需</em>过渡属性</li>
<li><em>可选</em>过渡属性</li>
</ul>
<p>让我们来讨论一下这两者。</p>
<h3 id="what-are-the-required-css-transition-properties">什么是必需 CSS 过渡属性</h3>
<p>创建 CSS 过渡的两个必需属性：</p>
<ul>
<li><code>transition-property</code></li>
<li><code>transition-duration</code></li>
</ul>
<h4 id="what-is-the-css-transition-property">什么是 <code>transition-property</code>？</h4>
<p>CSS 的 <code>transition-property</code> 指定你希望从初始态过渡到新状态的 CSS 属性。</p>
<h4 id="what-is-the-css-transition-duration-property">什么是 <code>transition-duration</code> ？</h4>
<p>CSS 的 <code>transition-duration</code> 属性定义了浏览器完成所选择元素过渡的时间长度。换句话说，<code>transition-duration</code> 设置从开始到结束所需的全部时间。</p>
<p><strong>注意以下几点：</strong></p>
<ul>
<li><code>transition-duration</code> 属性只接受毫秒（ms）或秒（s）的时间形式。</li>
<li>0 秒（<code>0s</code>）是 <code>transition-duration</code> 的默认值。因此，如果你不定义 <code>transition-duration</code> 属性，将不会有<a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/transitionend_event">过渡事件</a>发生。</li>
<li><code>transition-duration</code> 只接受 0 或正数值。如果你提供其他任何值浏览器将忽略它。</li>
</ul>
<h3 id="examples-of-the-required-css-transition-properties">必需 CSS 过渡属性的示例</h3>
<p>下面是两个必需 CSS 过渡属性的一些示例。</p>
<h4 id="3">如何在 3 秒内完成元素宽度的过渡</h4>
<pre><code class="language-css">img {
  width: 40%;
  transition-property: width;
  transition-duration: 3s;
}

img:hover {
  width: 100%;
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-transitions/js-cq27rd"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>transition-property</code> 告诉浏览器把 <code>img</code> 的 <code>width</code> 从它的初始值（<code>40%</code>）过渡到它的新状态（<code>100%</code>）。</li>
<li>使用 <code>transition-duration</code> 属性定义过渡从开始到结束持续 3 秒（<code>3s</code>）的时间。</li>
</ol>
<p>因此，浏览器将在 3 秒（<code>3s</code>）内从老值到新值间平滑地过渡，而不是立即把图片从初始宽度（<code>40%</code>）更改到新尺寸（<code>100%</code>）。</p>
<h4 id="5">如何在 5 秒内完成字体尺寸的过渡</h4>
<pre><code class="language-css">p {
  font-size: 1rem;
  transition-property: font-size;
  transition-duration: 5s;
}

p:hover {
  font-size: 7rem;
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-transitions/js-huvkzp"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>transition-property</code> 告知浏览器过渡 <code>p</code> 元素的 <code>font-size</code>。</li>
<li>使用 <code>transition-duration</code> 属性定义过渡从开始到结束持续 5 秒（<code>5s</code>）的时间。</li>
</ol>
<p>因此，浏览器将在 5 秒（<code>5s</code>）内从老值到新值间平滑地过渡，而不是立即把 <code>p</code> 的初始字体尺寸（<code>1rem</code>）更改到新尺寸（<code>7rem</code>）。</p>
<p>现在让我们讨论一下可选 CSS 过渡属性。</p>
<h3 id="what-are-the-optional-css-transition-properties">什么是可选 CSS 过渡属性</h3>
<p>这是两个可选 CSS 过渡属性：</p>
<ul>
<li><code>transition-timing-function</code></li>
<li><code>transition-delay</code></li>
</ul>
<h4 id="what-is-the-css-transition-timing-function-property">什么是 <code>transition-timing-function</code>？</h4>
<p>CSS 的 <code>transition-timing-function</code> 属性定义了所选元素实现过渡的时机（速度）。</p>
<p>换句话说，<code>transition-timing-function</code> 指定了在持续时间内的不同时间间隔实现过渡的速度。</p>
<p><code>transition-timing-function</code> 属性接受的值如下：</p>
<ul>
<li><code>ease</code>：开始时过渡缓慢，然后加快速度，并缓慢结束。<code>ease</code> 是属性 <code>transition-timing-function</code> 的默认值。它等价于 <code>cubic-bezier(0.25,0.1,0.25,1)</code>。</li>
<li><code>ease-in</code>：开始时过渡很慢，随后逐渐增加速度。它等价于 <code>cubic-bezier(0.42,0,1,1)</code>。</li>
<li><code>ease-out</code>：开始很快，结束时很慢。它等价于 <code>cubic-bezier(0,0,0.58,1)</code>。</li>
<li><code>ease-in-out</code>：开始和结束很慢。它等价于 <code>cubic-bezier(0.42,0,0.58,1)</code>。</li>
<li><code>linear</code>：在整个过渡的持续时间内使用一致的速度开始和结束过渡。它等价于 <code>cubic-bezier(0,0,1,1)</code>。</li>
<li><code>cubic-bezier(p1, p2, p3, p4)</code>：允许你定义<a href="https://www.cssportal.com/css-cubic-bezier-generator/">三次贝塞尔曲线</a>的值。</li>
</ul>
<h4 id="what-is-a-css-transition-delay-property">什么是 <code>transition-delay</code>？</h4>
<p>CSS 的 <code>transition-delay</code> 属性定义了浏览器在开始过渡前需要等待多长时间。</p>
<p><strong>注意以下几点：</strong></p>
<ul>
<li><code>transition-delay</code> 必须使用毫秒（ms）或秒（s）的形式。</li>
<li><code>0s</code> 是 <code>transition-delay</code> 的默认值，这会使过渡在浏览器将其应用到 HTML 元素时立即开始。</li>
<li>一个负值会使过渡从指定时间立即开始。举例来说，假设一个元素的 <code>transition-delay</code> 值设为 <code>-3s</code>，过渡将在 3 秒时立即执行。</li>
<li>一个正值会使过渡等待指定的延迟时间后开始。举例来说，假设一个元素的 <code>transition-delay</code> 值设为 <code>3s</code>，这次过渡将延迟 3 秒后开始。</li>
</ul>
<h3 id="examples-of-the-optional-css-transition-properties">可选 CSS 过渡属性的示例</h3>
<p>下面是两个可选 CSS 过渡属性的一些示例。</p>
<h4 id="easeout">如何使用 ease-out 速度完成元素宽度的过渡</h4>
<pre><code class="language-css">img {
  width: 40%;
  transition-property: width;
  transition-duration: 3s;
  transition-timing-function: ease-out;
}

img:hover {
  width: 100%;
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-transitions/js-tqzgmf"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>transition-property</code> 告知浏览器过渡 <code>img</code> 元素的宽度。</li>
<li>我们使用 <code>transition-duration</code> 属性定义过渡从开始到结束 3 秒（<code>3s</code>）的持续时间。</li>
<li>我们使用 <code>transition-timing-function</code> 属性快速地开始过渡然后缓慢地结束。</li>
</ol>
<h4 id="linear">如何使用 linear 速度完成元素宽度的过渡</h4>
<pre><code class="language-css">img {
  width: 40%;
  transition-property: width;
  transition-duration: 3s;
  transition-timing-function: linear;
}

img:hover {
  width: 100%;
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-transitions/js-1gqwai"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>transition-property</code> 告知浏览器过渡 <code>img</code> 元素的宽度。</li>
<li>我们使用 <code>transition-duration</code> 属性定义过渡从开始到结束 3 秒（<code>3s</code>）的持续时间。</li>
<li><code>transition-timing-function</code> 属性告诉浏览器将这个元素从初始宽度过渡到新尺寸时，采用恒定的过渡速度。</li>
</ol>
<h4 id="2">如何使用 2 秒的延迟完成元素宽度的过渡</h4>
<pre><code class="language-css">img {
  width: 40%;
  transition-property: width;
  transition-duration: 3s;
  transition-timing-function: linear;
  transition-delay: 2s;
}

img:hover {
  width: 100%;
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-transitions/js-ejjufi"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>transition-property</code> 告知浏览器过渡 <code>img</code> 元素的宽度。</li>
<li>我们使用 <code>transition-duration</code> 属性定义过渡从开始到结束 3 秒（<code>3s</code>）的持续时间。</li>
<li><code>transition-timing-function</code> 使用一个恒定的速度完成 <code>img</code> 元素宽度的过渡。</li>
<li>我们使用 <code>transition-delay</code> 属性在过渡的开始添加 2 秒（<code>2s</code>）的延迟。</li>
</ol>
<p>现在，我们了解了 CSS 过渡的属性，我们可以讨论一下它的缩写语法。</p>
<h2 id="shorthand-for-defining-the-css-transition-properties">CSS 过渡属性的缩写</h2>
<p>我们使用 <code>transition</code> 属性作为 <code>transition-property</code>、<code>transition-duration</code>、<code>transition-timing-function</code> 和 <code>transition-delay</code> 属性的缩写。</p>
<p>换句话说，我们不再这样写：</p>
<pre><code class="language-css">img {
  transition-property: width;
  transition-duration: 3s;
  transition-timing-function: linear;
  transition-delay: 2s;
}
</code></pre>
<p>你可以使用 <code>transition</code> 属性替换让你的代码更短，像这样：</p>
<pre><code class="language-css">img {
  transition: width 3s linear 2s;
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-transitions/js-vtvbpo"><strong>试着编辑它</strong></a></p>
<p>这是 <code>transition</code> 属性的语法：</p>
<pre><code class="language-css">transition: &lt;property-name&gt; &lt;duration&gt; &lt;timing-function&gt; &lt;delay&gt;;
</code></pre>
<p>注意你可以使用 <code>transition</code> 去定义多个 CSS 过渡属性的状态。</p>
<p><strong>看这个例子：</strong></p>
<pre><code class="language-css">img {
  width: 40%;
  opacity: 0.4;
  transition: width 3s linear, opacity 4s ease-out, transform 5s;
}

img:hover {
  width: 100%;
  opacity: 1;
  transform: rotate(45deg);
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-transitions/js-ajygzm"><strong>试着编辑它</strong></a></p>
<p>上面的片段使用逗号（<code>,</code>）去分隔我们应用在 <code>img</code> 元素上的每个过渡属性。</p>
<p>那么，现在你了解了 CSS 过渡是什么、它如何工作，我们来探讨一些 CSS 动画。</p>
<h2 id="what-is-css-animation">什么是 CSS 动画？</h2>
<p><strong>CSS 动画</strong> 提供了一个平滑、渐进的方式从一个关键帧到另一个关键帧为元素的样式增加动画。</p>
<h3 id="components-of-css-animations">CSS 动画的组成</h3>
<p>CSS 动画由两部分组成：</p>
<ol>
<li>关键帧</li>
<li>动画属性</li>
</ol>
<h3 id="what-are-css-keyframes">什么是 CSS <code>@keyframes</code>？</h3>
<p><strong>@keyframes</strong> 定义了你想要浏览器某关键时刻（帧）平滑地应用在元素上的样式。</p>
<h3 id="csskeyframes">CSS <code>@keyframes</code> 的语法</h3>
<p>CSS <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule">at 规则</a>中 @keyframes  由以下组成：</p>
<ol>
<li>一个 <code>@keyframes</code> 关键字</li>
<li>一个 <code>@keyframes</code> 名字</li>
<li>零个或多个关键帧块</li>
<li>关键帧选择器</li>
<li>关键帧样式声明</li>
</ol>
<p><strong>看这个插图：</strong></p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2023/09/css-animation-keyframes-illustration-codesweetly.png" alt="剖析 CSS @keyframes" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>剖析 CSS @keyframes</figcaption>
</figure>
<p>一个 CSS <code>@keyframes</code> 由一个关键字、一个名字、一个关键帧块组成。</p>
<h3 id="csskeyframes">CSS @keyframes 的示例</h3>
<p>下面是 CSS @keyframes 的示例</p>
<h4 id="changecolor">如何定义 <code>change-color</code> 的关键帧</h4>
<pre><code class="language-css">@keyframes change-color {
  /* 最初的关键帧 */
  0% {background-color: purple;}
  /* 最后的关键帧 */
  100% {background-color: yellow;}
}
</code></pre>
<p>在上面片段中我们做了什么：</p>
<ol>
<li>我们创建了一个 <code>@keyframes</code> 命名为 <code>change-color</code>。</li>
<li>我们定义了一个关键帧，供浏览器在关联元素的动画处于 <code>0%</code> 持续时间时应用。</li>
<li>我们定义了一个关键帧，供浏览器在关联元素的动画处于 <code>100%</code> 持续时间时应用。</li>
</ol>
<p><strong>注意：</strong></p>
<ul>
<li>你可以把你的 <code>@keyframes</code> 按照你希望的随意命名。</li>
<li><code>0%</code> 等价于关键字 <code>from</code>，<code>100%</code> 等价于关键字 <code>to</code>。也就是说，上面的代码片段等价于下面的：</li>
</ul>
<pre><code class="language-css">@keyframes change-color {
  /* 最初的关键帧 */
  from {background-color: purple;} 
  /* 最后的关键帧 */
  to {background-color: yellow;} 
}
</code></pre>
<ul>
<li>一个动画的开始和结束状态（<code>from</code> 和 <code>to</code>）是可选的。</li>
<li>假设你省略了 <code>@keyframes</code> 的开始或结束状态，这种情况下，浏览器将使用元素的现有样式作为起始/结束状态。</li>
<li><code>!important</code> 在关键帧中无效，浏览器会忽略任何带有 <code>!important</code> 的关键帧声明。</li>
</ul>
<p>让我们看另一个例子。</p>
<h4 id="shapeimage">如何定义 <code>shape-image</code> 的关键帧</h4>
<pre><code class="language-css">@keyframes shape-image {
  0% { width: 40%; border: 5px solid blue;}
  40% { width: 70%; border: 1px solid red; border-radius: 50%;}
  75% { width: 50%; border: 30px solid green;}
  100% { width: 100%; border: 7px solid purple;}
}
</code></pre>
<p>在上面片段中我们做了什么：</p>
<ol>
<li>我们创建了 <code>@keyframes</code> <a href="https://codesweetly.com/css-ruleset">规则集</a> 命名为 <code>shape-image</code>。</li>
<li>我们定义了 4 个关键帧，供浏览器在关联元素的动画处于指定关键时刻时应用。</li>
</ol>
<p><strong>提示：</strong> 在 JavaScript 中使用 <a href="https://developer.mozilla.org/en-US/docs/Web/API/CSSKeyframesRule">CSSKeyframesRule</a> 接口访问 CSS <code>@keyframes</code>。</p>
<p>那么，现在我们知道了 CSS @keyframes 规则集，我们可以讨论另一个 CSS 动画的组成部分了—— <em>animation 属性</em>。</p>
<h2 id="what-are-css-animation-properties">什么是 CSS animation 属性？</h2>
<p><strong>CSS animation 属性</strong> 告知浏览器你希望应用在指定元素上的动画。</p>
<p>换句话说，CSS <code>animation</code> 描述了动画的属性，例如它的名字、持续时间、方向、迭代次数。</p>
<p>下面是 CSS 动画的 9 种属性：</p>
<ul>
<li><code>animation-name</code></li>
<li><code>animation-duration</code></li>
<li><code>animation-timing-function</code></li>
<li><code>animation-delay</code></li>
<li><code>animation-iteration-count</code></li>
<li><code>animation-direction</code></li>
<li><code>animation-play-state</code></li>
<li><code>animation-fill-mode</code></li>
<li><code>animation</code></li>
</ul>
<p>让我们逐个讨论一下。</p>
<h3 id="what-is-the-css-animation-name-property">什么是 CSS <code>animation-name</code> 属性？</h3>
<p>CSS <code>animation-name</code> 属性定义了你希望应用在指定元素上的 <code>@keyframes</code> 包含的样式的名字。</p>
<p><strong>看这个例子：</strong></p>
<pre><code class="language-css">div {
  width: 150px;
  height: 150px;
  animation-name: change-color;
}

@keyframes change-color {
  from {background-color: purple;}
  to {background-color: yellow;}
}
</code></pre>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>animation-name</code> 指定了我们希望应用到 <code>div</code> 元素上的 <code>@keyframes</code>。</li>
<li>我们创建了一个名为 <code>change-color</code> 的 <code>@keyframes</code> 规则集。</li>
<li>我们定义了 <code>div</code> 元素的动画在 <code>0%</code> 和 <code>100%</code> 时两个关键帧给浏览器使用。</li>
</ol>
<p><strong>提示：</strong> 你可以使用关键字 <code>none</code> 不激活动画。</p>
<h3 id="what-is-the-css-animation-duration-property">什么是 CSS <code>animation-duration</code> 属性？</h3>
<p>CSS <code>animation-duration</code> 属性定义了完成一个动画循环的事件。</p>
<p><strong>注意以下几点：</strong></p>
<ul>
<li><code>animation-duration</code> 属性只接受毫秒（ms）或秒（s）的时间形式。</li>
<li><code>animation-duration</code> 值只接受 0 或是整数。否则，浏览器将忽略这条声明。</li>
<li>0 秒（<code>0s</code>）是 <code>animation-duration</code> 的默认值。</li>
<li>假设 <code>0s</code> 是 <code>animation-duration</code> 的值。在这种情况下，浏览器仍将通过触发 <a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/animationstart_event"><code>animationStart</code></a> 和 <a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/animationend_event"><code>animationEnd</code></a> 事件来执行动画。但是由 <a href="https://codesweetly.com/css-animations-explained#what-is-an-animation-fill-mode-property-in-css"><code>animation-fill-mode</code></a> 值决定动画是否可见。比如，你设置 <code>animation-fill-mode</code> 为 <code>none</code>，动画则是不可见的。</li>
</ul>
<p>让我们看一些 <code>animation-duration</code> 属性的例子。</p>
<h4 id="3">如何在 3 秒内完成更改元素的颜色的动画</h4>
<pre><code class="language-css">div {
  width: 150px;
  height: 150px;
  animation-name: change-color;
  animation-duration: 3s;
}

@keyframes change-color {
  from {background-color: purple;}
  to {background-color: yellow;}
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-animations/js-h6mb4k"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>animation-name</code> 属性指定了我们希望用在 <code>div</code> 元素上的 <code>@keyframes</code>。</li>
<li><code>animation-duration</code> 属性设置了动画一个循环的运行时间在 3 秒（<code>3s</code>）内。</li>
<li>我们创建了 <code>change-color</code> 关键帧<a href="https://codesweetly.com/css-ruleset">规则集</a>。</li>
<li>我们定义了 <code>div</code> 元素的动画在 <code>0%</code> 和 <code>100%</code> 时两个关键帧给浏览器使用。</li>
</ol>
<p>因此，浏览器将创建一个从第一帧到最后持续 3 秒的平滑的 <code>change-color</code> 动画。</p>
<h4 id="7">如何在 7 秒内完成更改图片边框和宽度的动画</h4>
<pre><code class="language-css">img {
  animation-name: shape-image;
  animation-duration: 7s;
}

@keyframes shape-image {
  0% { width: 40%; border: 5px solid blue;}
  40% { width: 70%; border: 1px solid red; border-radius: 50%;}
  75% { width: 50%; border: 30px solid green;}
  100% { width: 100%; border: 7px solid purple;}
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-animations/js-prumgo"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>animation-name</code> 属性指定了我们希望应用到 <code>img</code> 元素的 <code>@keyframes</code>。</li>
<li><code>animation-duration</code> 属性设置动画一个循环的运行时长为 7 秒（<code>7s</code>）。</li>
<li>我们创建了 <code>shape-image</code> 的关键帧规则集。</li>
<li>我们定义了四个关键帧，以便浏览器在图像动画达到指定关键时刻时应用。</li>
</ol>
<p>因此，浏览器将从 <code>shape-image</code> 的第一帧到最后一帧创建一个流畅的 7 秒的动画。</p>
<h3 id="what-is-the-css-animation-timing-function-property">什么是 CSS <code>animation-timing-function</code> 属性？</h3>
<p>CSS 的 <code>animation-timing-function</code> 属性定义了动画在整个持续时间内的实现时机（速度）。</p>
<p>换句话说，<code>animation-timing-function</code> 属性指定了动画在其持续时间内各个间隔的实现速度。</p>
<p><code>animation-timing-function</code> 属性接受的值如下：</p>
<ul>
<li><code>ease</code>：慢慢地开始动画，然后加速，并慢慢地结束动画。<code>ease</code> 是 <code>animation-timing-function</code> 属性的默认值。它等价于 <code>cubic-bezier(0.25, 0.1, 0.25, 1)</code>。</li>
<li><code>ease-in</code>：用一个递增的速度慢慢地开始动画。它等价于 <code>cubic-bezier(0.42, 0, 1, 1)</code>。</li>
<li><code>ease-out</code>：动画开始很快，然后慢慢的结束动画。它等价于 <code>cubic-bezier(0, 0, 0.58, 1)</code>。</li>
<li><code>ease-in-out</code>：慢慢地开始并慢慢地结束动画。它等价于 <code>cubic-bezier(0.42, 0, 0.58, 1)</code>。</li>
<li><code>linear</code>：在整个动画持续时间内使用一致的速度开始、结束动画。它等价于 <code>cubic-bezier(0, 0, 1, 1)</code>。</li>
<li><code>cubic-bezier(p1, p2, p3, p4)</code>：允许你定义<a href="https://www.cssportal.com/css-cubic-bezier-generator/">三次贝塞尔曲线</a>的值。</li>
</ul>
<p>然我们看一些 <code>animation-timing-function</code> 属性的例子。</p>
<h4 id="">如何使用线性速度完成更改元素宽度的动画</h4>
<pre><code class="language-css">div {
  width: 150px;
  height: 150px;
  background-color: purple;
  animation-name: change-width;
  animation-duration: 7s;
  animation-timing-function: linear;
}

@keyframes change-width {
  from {width: 50px;}
  to {width: 100%;}
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-animations/js-tzwrdc"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>animation-name</code> 属性制定了我们希望应用到 <code>div</code> 元素的 <code>@keyframes</code>。</li>
<li><code>animation-duration</code> 属性设置动画一个循环的运行时长为 7 秒（<code>7s</code>）。</li>
<li><code>linear</code> 函数应用一个一致的速度到 <code>div</code> 元素的动画上。</li>
<li>我们创建一个名为 <code>change-width</code> 关键帧规则集。</li>
<li>我们为浏览器定义了两个关键帧，分别在 <code>div</code> 动画的持续时间为百分之零（<code>0%</code>）和百分之一百（<code>100%</code>）时应用。</li>
</ol>
<p>因此，浏览器将从 <code>change-width</code> 的第一帧到最后一帧创建一个流畅的 7 秒的动画。</p>
<p>让我们看另一个例子。</p>
<h4 id="easeinout">如何使用 ease-in-out 和 线性速度完成更改元素宽度的动画</h4>
<pre><code class="language-css">div {
  width: 150px;
  height: 150px;
  color: white;
  animation-name: change-width;
  animation-duration: 7s;
}

.first-div {
  background-color: purple;
  animation-timing-function: ease-in-out;
}

.second-div {
  background-color: orange;
  animation-timing-function: linear;
}

@keyframes change-width {
  from {width: 50px;}
  to {width: 100%;}
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-animations/js-janmqa"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>animation-name</code> 属性制定了我们希望应用到 <code>div</code> 元素的 <code>@keyframes</code>。</li>
<li><code>animation-duration</code> 属性设置动画一个循环的运行时长为 7 秒（<code>7s</code>）。</li>
<li>我们使用 <code>ease-in-out</code> 函数在 <code>first-div</code> 上应用一个慢慢开始并慢慢结束的动画。</li>
<li><code>linear</code> 函数在 <code>second-div</code> 上用一个一致的速度的动画。</li>
<li>我们创建了名为 <code>change-width</code> 的关键帧规则集。</li>
<li>我们为浏览器定义了两个关键帧，分别在 <code>div</code> 动画的持续时间为百分之零（<code>0%</code>）和百分之一百（<code>100%</code>）时应用。</li>
</ol>
<p>因此，浏览器将从 <code>change-width</code> 的第一帧到最后一帧创建一个流畅的 7 秒的动画。</p>
<h3 id="what-is-the-css-animation-delay-property">什么是 CSS <code>animation-delay</code> 属性？</h3>
<p>CSS 的 <code>animation-delay</code> 属性定义了浏览器在开始动画之前需要等待多长时间。</p>
<p>换句话说，使用 <code>animation-delay</code> 去指定动画是应该立即开始、从指定时间开始、还是稍后（一段延迟之后）开始。</p>
<p><strong>注意以下几点：</strong></p>
<ul>
<li><code>animation-delay</code> 属性必须是毫秒（<code>ms</code>）或是秒（<code>s</code>）作为单位。</li>
<li><code>0s</code> 是 <code>animation-delay</code> 的默认值，这会使动画在浏览器将其应用到 HTML 元素时立即开始。</li>
<li>一个负值会使动画从指定时间立即开始。举例来说，假设一个元素的 <code>animation-delay</code> 值设为 <code>-3s</code>，动画将在 3 秒时立即开始。</li>
<li>一个正值会使动画等待指定时间过后开始。举例来说，假设一个元素的 <code>animation-delay</code> 值设为 <code>3s</code>，这次动画将延迟 3 秒后开始。</li>
</ul>
<p>让我们看一些 <code>animation-delay</code> 属性的例子。</p>
<h4 id="4">如何 4 秒延迟后完成更改元素宽度的动画</h4>
<pre><code class="language-css">div {
  width: 150px;
  height: 150px;
  color: white;
  animation-name: change-width;
  animation-duration: 7s;
}

.first-div {
  background-color: purple;
  animation-timing-function: ease-in-out;
}

.second-div {
  background-color: orange;
  animation-timing-function: linear;
  animation-delay: 4s;
}

@keyframes change-width {
  from {width: 50px;}
  to {width: 100%;}
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-animations/js-iidpmk"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>animation-name</code> 属性制定了我们希望应用到 <code>div</code> 元素的 <code>@keyframes</code>。</li>
<li><code>animation-duration</code> 属性设置动画一个循环的运行时长为 7 秒（<code>7s</code>）。</li>
<li>我们使用 <code>ease-in-out</code> 函数在 <code>first-div</code> 上应用一个慢慢开始并慢慢结束的动画。</li>
<li><code>linear</code> 函数在 <code>second-div</code> 上用一个一致的速度的动画。</li>
<li><code>animation-delay</code> 属性在开始 <code>second-div</code> 的动画时应用了一个 4 秒（<code>4s</code>）的延迟。</li>
<li>我们创建了名为 <code>change-width</code> 的关键帧规则集。</li>
<li>我们为浏览器定义了两个关键帧，分别在 <code>div</code> 动画的持续时间为百分之零（<code>0%</code>）和百分之一百（<code>100%</code>）时应用。</li>
</ol>
<p>因此，浏览器会延迟 <code>second-div</code> 的动画四秒，而立即开始 <code>first-div</code> 的动画。</p>
<p>下面是 <code>animation-delay</code> 属性的另一个例子。</p>
<h4 id="">如何从动画序列的第四秒开始完成更改元素宽度的动画</h4>
<pre><code class="language-css">div {
  width: 150px;
  height: 150px;
  color: white;
  animation-name: change-width;
  animation-duration: 7s;
}

.first-div {
  background-color: purple;
  animation-timing-function: ease-in-out;
}

.second-div {
  background-color: orange;
  animation-timing-function: linear;
  animation-delay: -4s;
}

@keyframes change-width {
  from {width: 50px;}
  to {width: 100%;}
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-animations/js-6xga4t"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>animation-name</code> 属性制定了我们希望应用到 <code>div</code> 元素的 <code>@keyframes</code>。</li>
<li><code>animation-duration</code> 属性设置动画一个循环的运行时长为 7 秒（<code>7s</code>）。</li>
<li>我们使用 <code>ease-in-out</code> 函数在 <code>first-div</code> 上应用一个慢慢开始并慢慢结束的动画。</li>
<li><code>linear</code> 函数在 <code>second-div</code> 上用一个一致的速度的动画。</li>
<li><code>animation-delay</code> 属性使 <code>second-div</code> 的动画从动画序列的第四秒开始。</li>
<li>我们创建了名为 <code>change-width</code> 的关键帧规则集。</li>
<li>我们为浏览器定义了两个关键帧，分别在 <code>div</code> 动画的持续时间为百分之零（<code>0%</code>）和百分之一百（<code>100%</code>）时应用。</li>
</ol>
<p>因此，浏览器会在第四秒立即开始 <code>second-div</code> 的动画。</p>
<h3 id="what-is-the-css-animation-iteration-count-property">什么是 CSS <code>animation-iteration-count</code> 属性？</h3>
<p>CSS 的 <code>animation-iteration-count</code> 属性定义了浏览器应重复动画的次数。</p>
<p><strong>注意以下几点：</strong></p>
<ul>
<li><code>1</code> 是 <code>animation-iteration-count</code> 的默认值。</li>
<li><code>animation-iteration-count</code> 属性接受非整数值，<code>0.5</code> 告诉浏览器播放单个动画循环的一半。</li>
<li><code>animation-iteration-count</code> <em>不接受</em>赋值。</li>
<li><code>infinite</code> 意味着浏览器将一直重复这个动画。</li>
</ul>
<p>下面是一些例子。</p>
<h4 id="">如何完成两次更改元素宽度的动画</h4>
<pre><code class="language-css">div {
  width: 70px;
  height: 50px;
  background-color: purple;
  animation-name: change-width;
  animation-duration: 5s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: 2;
}

@keyframes change-width {
  from {width: 70px;}
  to {width: 100%;}
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-animations/js-vbcswe"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>animation-name</code> 属性制定了我们希望应用到 <code>div</code> 元素的 <code>@keyframes</code>。</li>
<li><code>animation-duration</code> 属性设置动画一个循环的运行时长为 5 秒（<code>5s</code>）。</li>
<li>我们使用 <code>ease-in-out</code> 函数在 <code>div</code> 上应用一个慢慢开始并慢慢结束的动画。</li>
<li><code>animation-iteration-count</code> 属性告诉浏览器运行这个动画两次。</li>
<li>我们创建了名为 <code>change-width</code> 的关键帧规则集。</li>
<li>我们为浏览器定义了两个关键帧，分别在 <code>div</code> 动画的持续时间为百分之零（<code>0%</code>）和百分之一百（<code>100%</code>）时应用。</li>
</ol>
<p>因此，浏览器将运行 <code>div</code> 的动画两次。</p>
<p>下面是另一个 <code>animation-iteration-count</code> 属性的例子。</p>
<h4 id="">如何无限重复更改元素宽度的动画</h4>
<pre><code class="language-css">div {
  width: 70px;
  height: 50px;
  animation-name: change-width;
  animation-duration: 5s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}

@keyframes change-width {
  from {width: 70px; background-color: purple;}
  to {width: 100%; background-color: orange;}
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-animations/js-p1zwk5"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>animation-name</code> 属性制定了我们希望应用到 <code>div</code> 元素的 <code>@keyframes</code>。</li>
<li><code>animation-duration</code> 属性设置动画一个循环的运行时长为 5 秒（<code>5s</code>）。</li>
<li>我们使用 <code>ease-in-out</code> 函数在 <code>div</code> 上应用一个慢慢开始并慢慢结束的动画。</li>
<li><code>animation-iteration-count</code> 属性告诉浏览器无限次地运行这个动画。</li>
<li>我们创建了名为 <code>change-width</code> 的关键帧规则集。</li>
<li>我们为浏览器定义了两个关键帧，分别在 <code>div</code> 动画的持续时间为百分之零（<code>0%</code>）和百分之一百（<code>100%</code>）时应用。</li>
</ol>
<p>因此，浏览器将无限次地运行 <code>div</code> 的动画。</p>
<h3 id="cssanimationdirection">什么是 CSS <code>animation-direction</code> 属性？</h3>
<p><code>animation-direction</code> 属性指定动画的第一次迭代是正向还是反向。它还定义浏览器是否应该改变后续迭代的方向。</p>
<p><code>animation-direction</code> 可接受的值：</p>
<ul>
<li><code>normal</code>：正常的方向播放动画（也就是正向），<code>normal</code> 是 <code>animation-direction</code> 的默认值。</li>
<li><code>reverse</code>：相反的方向播放动画（反向）。</li>
<li><code>alternate</code>：第一次动画循环正向播放，后续迭代在方向与正向之间交替。</li>
<li><code>alternate-reverse</code>：第一次动画循环反向播放，后续迭代在正向与反向之间交替。</li>
</ul>
<p>下面是一些例子。</p>
<h4 id="">如何每次都以反向开始完成改变元素宽度的动画</h4>
<pre><code class="language-css">div {
  width: 70px;
  height: 50px;
  animation-name: change-width;
  animation-duration: 5s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-direction: reverse;
}

@keyframes change-width {
  from {width: 70px; background-color: purple;}
  to {width: 100%; background-color: orange;}
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-animations/js-d2n3zt"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>animation-name</code> 属性制定了我们希望应用到 <code>div</code> 元素的 <code>@keyframes</code>。</li>
<li><code>animation-duration</code> 属性设置动画一个循环的运行时长为 5 秒（<code>5s</code>）。</li>
<li>我们使用 <code>ease-in-out</code> 函数在 <code>div</code> 上应用一个慢慢开始并慢慢结束的动画。</li>
<li><code>animation-iteration-count</code> 属性告诉浏览器无限次地运行这个动画。</li>
<li><code>animation-direction</code> 属性让每次动画反向开始。</li>
<li>我们创建了名为 <code>change-width</code> 的关键帧规则集。</li>
<li>我们为浏览器定义了两个关键帧，分别在 <code>div</code> 动画的持续时间为百分之零（<code>0%</code>）和百分之一百（<code>100%</code>）时应用。</li>
</ol>
<p>下面是 <code>animation-direction</code> 属性的另一个例子。</p>
<h4 id="">如何交替动画方向地完成更改元素宽度的动画</h4>
<pre><code class="language-css">div {
  width: 70px;
  height: 50px;
  animation-name: change-width;
  animation-duration: 5s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}

@keyframes change-width {
  from {width: 70px; background-color: purple;}
  to {width: 100%; background-color: orange;}
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-animations/js-ld9kms"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>animation-name</code> 属性制定了我们希望应用到 <code>div</code> 元素的 <code>@keyframes</code>。</li>
<li><code>animation-duration</code> 属性设置动画一个循环的运行时长为 5 秒（<code>5s</code>）。</li>
<li>我们使用 <code>ease-in-out</code> 函数在 <code>div</code> 上应用一个慢慢开始并慢慢结束的动画。</li>
<li><code>animation-iteration-count</code> 属性告诉浏览器无限次地运行这个动画。</li>
<li><code>animation-direction</code> 属性让每次动画都交替方向。</li>
<li>我们创建了名为 <code>change-width</code> 的关键帧规则集。</li>
<li>我们为浏览器定义了两个关键帧，分别在 <code>div</code> 动画的持续时间为百分之零（<code>0%</code>）和百分之一百（<code>100%</code>）时应用。</li>
</ol>
<h3 id="cssanimationplaystate">什么是 CSS <code>animation-play-state</code> 属性？</h3>
<p>CSS 的 <code>animation-play-state</code> 属性定义了浏览器是在运行还是暂停特定动画。</p>
<p><code>animation-play-state</code> 属性接受的值：</p>
<ul>
<li><code>running</code>：指定浏览器运行动画。<code>running</code> 是 <code>animation-play-state</code> 的默认值。</li>
<li><code>paused</code>：指定浏览器暂停动画。</li>
</ul>
<p><strong>看这个例子：</strong></p>
<pre><code class="language-css">div {
  width: 70px;
  height: 50px;
  animation-name: change-width;
  animation-duration: 5s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}

div:hover {
  animation-play-state: paused;
}

@keyframes change-width {
  from {width: 70px; background-color: purple;}
  to {width: 100%; background-color: orange;}
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-animations/js-kbommn"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>animation-name</code> 属性制定了我们希望应用到 <code>div</code> 元素的 <code>@keyframes</code>。</li>
<li><code>animation-duration</code> 属性设置动画一个循环的运行时长为 5 秒（<code>5s</code>）。</li>
<li>我们使用 <code>ease-in-out</code> 函数在 <code>div</code> 上应用一个慢慢开始并慢慢结束的动画。</li>
<li><code>animation-iteration-count</code> 属性告诉浏览器无限次地运行这个动画。</li>
<li><code>animation-direction</code> 属性让每次动画都交替方向。</li>
<li>我们在 <code>div</code> 的 hover <a href="https://codesweetly.com/css-pseudo-selectors">伪类</a>上使用了 <code>animation-play-state</code>，以便在用户将鼠标移到 <code>div</code> 元素上时暂停动画。</li>
<li>我们创建了名为 <code>change-width</code> 的关键帧规则集。</li>
<li>我们为浏览器定义了两个关键帧，分别在 <code>div</code> 动画的持续时间为百分之零（<code>0%</code>）和百分之一百（<code>100%</code>）时应用。</li>
</ol>
<h3 id="cssanimationfillmode">什么是 CSS <code>animation-fill-mode</code> 属性？</h3>
<p>CSS 的 <code>animation-fill-mode</code> 属性定义了浏览器在动画运行之前（或之后）应该应用于元素的样式。</p>
<p><code>animation-fill-mode</code> 可接受的值：</p>
<ul>
<li><code>none</code>：浏览器将<em>不会</em>在动画运行之后或之前应用样式。<code>none</code> 是 <code>animation-fill-mode</code> 的默认值。</li>
<li><code>forwards</code>：当动画结束，元素将保留最后动画帧的样式声明。（注意：<code>animation-direction</code> 和 <code>animation-iteration-count</code> 属性将决定最后一帧。）</li>
<li><code>backwards</code>：在 <code>animation-delay</code> 期间，动画将保留最初动画帧的样式声明。（注意：<code>animation-direction</code> 属性决定第一帧。）</li>
<li><code>both</code>：浏览器将同时应用 <code>forwards</code> 和 <code>backwards</code> 规则。因此，动画属性将在两个方向上扩展。</li>
</ul>
<p>下面是一些例子：</p>
<h4 id="">如何在动画结束为元素增加样式</h4>
<pre><code class="language-css">div {
  width: 70px;
  height: 50px;
  background-color: green;
  animation-name: change-width;
  animation-duration: 5s;
  animation-timing-function: ease-in-out;
  animation-fill-mode: forwards;
}

@keyframes change-width {
  from {width: 70px; background-color: purple;}
  to {width: 100%; background-color: orange;}
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-animations/js-lkc7mw"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>animation-name</code> 属性制定了我们希望应用到 <code>div</code> 元素的 <code>@keyframes</code>。</li>
<li><code>animation-duration</code> 属性设置动画一个循环的运行时长为 5 秒（<code>5s</code>）。</li>
<li>我们使用 <code>ease-in-out</code> 函数在 <code>div</code> 上应用一个慢慢开始并慢慢结束的动画。</li>
<li><code>animation-fill-mode</code> 将告诉浏览器当动画结束时保留最后的关键帧样式声明。</li>
<li>我们创建了名为 <code>change-width</code> 的关键帧规则集。</li>
<li>我们为浏览器定义了两个关键帧，分别在 <code>div</code> 动画的持续时间为百分之零（<code>0%</code>）和百分之一百（<code>100%</code>）时应用。</li>
</ol>
<p>下面是 <code>animation-fill-mode</code> 属性的另一个例子。</p>
<h4 id="">如何在动画延迟这段时间增加样式</h4>
<pre><code class="language-css">div {
  width: 70px;
  height: 50px;
  background-color: green;
  animation-name: change-width;
  animation-duration: 5s;
  animation-timing-function: ease-in-out;
  animation-delay: 3s;
  animation-fill-mode: backwards;
}

@keyframes change-width {
  from {width: 70px; background-color: purple;}
  to {width: 100%; background-color: orange;}
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-animations/js-nfmq3r"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>animation-name</code> 属性制定了我们希望应用到 <code>div</code> 元素的 <code>@keyframes</code>。</li>
<li><code>animation-duration</code> 属性设置动画一个循环的运行时长为 5 秒（<code>5s</code>）。</li>
<li>我们使用 <code>ease-in-out</code> 函数在 <code>div</code> 上应用一个慢慢开始并慢慢结束的动画。</li>
<li><code>animation-fill-mode</code> 将告诉浏览器在 <code>animation-delay</code> 期间保留最开始的关键帧样式声明。</li>
<li>我们创建了名为 <code>change-width</code> 的关键帧规则集。</li>
<li>我们为浏览器定义了两个关键帧，分别在 <code>div</code> 动画的持续时间为百分之零（<code>0%</code>）和百分之一百（<code>100%</code>）时应用。</li>
</ol>
<p>让我们看 <code>animation-fill-mode</code> 属性的第三个例子。</p>
<h4 id="">如何在动画延迟时和完成动画后增加样式</h4>
<pre><code class="language-css">div {
  width: 70px;
  height: 50px;
  background-color: green;
  animation-name: change-width;
  animation-duration: 5s;
  animation-timing-function: ease-in-out;
  animation-delay: 3s;
  animation-fill-mode: both;
}

@keyframes change-width {
  from {width: 70px; background-color: purple;}
  to {width: 100%; background-color: orange;}
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-animations/js-gbypmt"><strong>试着编辑它</strong></a></p>
<p>在上面片段中我们做了什么：</p>
<ol>
<li><code>animation-name</code> 属性制定了我们希望应用到 <code>div</code> 元素的 <code>@keyframes</code>。</li>
<li><code>animation-duration</code> 属性设置动画一个循环的运行时长为 5 秒（<code>5s</code>）。</li>
<li>我们使用 <code>ease-in-out</code> 函数在 <code>div</code> 上应用一个慢慢开始并慢慢结束的动画。</li>
<li><code>animation-fill-mode</code> 将告诉浏览器同时应用 <code>forwards</code> 和 <code>backwards</code> 两条规则。</li>
<li>我们创建了名为 <code>change-width</code> 的关键帧规则集。</li>
<li>我们为浏览器定义了两个关键帧，分别在 <code>div</code> 动画的持续时间为百分之零（<code>0%</code>）和百分之一百（<code>100%</code>）时应用。</li>
</ol>
<h2 id="cssanimation">什么是 CSS <code>animation</code> 属性？</h2>
<p>我们使用 <code>animation</code> 属性作为它们的缩写：</p>
<ul>
<li><code>animation-name</code></li>
<li><code>animation-duration</code></li>
<li><code>animation-timing-function</code></li>
<li><code>animation-delay</code></li>
<li><code>animation-iteration-count</code></li>
<li><code>animation-direction</code></li>
<li><code>animation-play-state</code></li>
<li><code>animation-fill-mode</code></li>
</ul>
<p>换句话说，不需要写这些：</p>
<pre><code class="language-css">div {
  animation-name: change-width;
  animation-duration: 5s;
  animation-timing-function: ease-in-out;
  animation-delay: 2s;
  animation-iteration-count: 3;
  animation-direction: alternate;
  animation-play-state: running;
  animation-fill-mode: both;
}
</code></pre>
<p>另外，你也可以使用 <code>animation</code> 属性缩短你的代码，像是这样：</p>
<pre><code class="language-css">div {
  animation: 5s ease-in-out 2s 3 alternate both running change-width;
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-animations/js-37ccew"><strong>试着编辑它</strong></a></p>
<p>这是 <code>animation</code> 属性的语法：</p>
<pre><code class="language-css">animation: animation-duration animation-timing-function animation-delay animation-iteration-count animation-direction animation-fill-mode animation-play-state animation-name;
</code></pre>
<p><strong>注意：</strong></p>
<ul>
<li>时间值的排列方式很重要。浏览器将第一个时间值视为 <code>animation-duration</code>，而将第二个时间值分配给 <code>animation-delay</code>。</li>
<li>最好将 <code>animation-name</code> 放在最后，不然，浏览器可能赋值 <code>animation-name</code> 到其他属性。</li>
<li>你可以使用 <code>animation</code> 属性应用多个 <code>@keyframes</code> <a href="https://codesweetly.com/css-ruleset">规则集</a>到一个元素。看这个例子：</li>
</ul>
<pre><code class="language-css">div {
  width: 70px;
  height: 70px;
  background-color: green;
  animation: 
    5s ease-in-out 3s 3 alternate both change-width, 
    5s 3s infinite alternate both change-shape, 
    5s 3s infinite rotate-hue;
}

@keyframes change-width {
  from {width: 70px; background-color: purple;}
  to {width: 100%; background-color: orange;}
}

@keyframes change-shape {
  from {border-radius: 0%; border: 1px solid blue;}
  to {border-radius: 50%; border: 7px solid green;}
}

@keyframes rotate-hue {
  from {filter: hue-rotate(0deg);}
  to {filter: hue-rotate(360deg);}
}
</code></pre>
<p><a href="https://codesweetly.com/try-it-sdk/css/css-animations/js-4lyg4d"><strong>试着编辑它</strong></a></p>
<p>上方的片段使用逗号分隔了三个 <code>@keyframes</code> 并应用到 <code>div</code> 元素上。</p>
<p><strong>注意：</strong> 我们用了 <a href="https://www.quackit.com/css/functions/css_hue-rotate_function.cfm"><code>hue-rotate()</code></a> 函数去改变了色调。</p>
<h2 id="important-stuff-to-know-about-css-transitions-and-animations">CSS 过渡和动画的重要知识要点</h2>
<ol>
<li>你不能为所有的 CSS 属性增加动画。可以去看看 MDN 的<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animated_properties">可动画化的 CSS 属性</a>文章，以查看可以进行动画处理的属性列表。</li>
<li>CSS 过渡和动画对于大多数 CSS 属性来说是<a href="https://codesweetly.com/web-tech-terms-e#expensive-operation-computing">昂贵的操作</a>，除了 <code>opacity</code> 和 <code>transform</code>。</li>
<li>应该注意 CSS 过渡可能通过元素的堆叠顺序引起<a href="https://dzhavat.github.io/2021/02/18/debugging-layout-repaint-issues-triggered-by-css-transition.html">布局的重绘问题</a>，</li>
</ol>
<h2 id="wrapping-up">总结</h2>
<p>在这这篇文章中，我们讨论了 CSS 过渡和动画之间的不同，也用了一些例子来讨论应该如何使用它。</p>
<p>感谢阅读！</p>
<h3 id="reacttypescript">这还有些有用的 React Typescript 资源</h3>
<p>我写了一本有关<a href="https://amzn.to/3Pa4bI4">如何创建 NPM 包</a>的书！</p>
<p>这是一本对初学者友好的书，你可以像是专家一样从零开始去创建、测试、发布一个NPM包。</p>
<a href="https://amzn.to/3Pa4bI4">
  <figure class="kg-card kg-card-image kg-card-hascaption">
      <img src="https://www.freecodecamp.org/news/content/images/2023/09/creating-npm-package-banner-codesweetly.png" alt="可以在 Amazon 上找到这本如何创建 NPM 包" class="kg-image" width="600" height="400" loading="lazy">
      <figcaption>可以在 Amazon 上找到这本书</figcaption>
  </figure>
</a>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ CSS Flexbox 手册——附带实用示例的完整指南 ]]>
                </title>
                <description>
                    <![CDATA[ Flexbox 是一个有用的工具，用于为网页创建美观且响应式的布局。在本指南中，你将学习像专业人士一样开始使用 CSS Flexbox 所需的一切知识。我们还将学习大量练习示例。 如果你是初学者 web 开发人员，本指南对你来说是一份完美的资源。如果你是经验丰富的开发人员，想要提高响应式网页设计技能，它也会很有用。 目录  * 什么是 Flexbox  * 使用 Flexbox 有什么好处  * 主轴和交叉轴  * Flex 容器和 Flex 项  * 了解 Flex 和 Inline-flex  * display: flex  * display: inline-flex  * Flex 容器属性  * flex-direction 属性  ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/the-css-flexbox-handbook/</link>
                <guid isPermaLink="false">6604e2b96f02f80413b53aa1</guid>
                
                    <category>
                        <![CDATA[ Flexbox ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ huqi ]]>
                </dc:creator>
                <pubDate>Thu, 28 Mar 2024 04:53:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2024/03/The-CSS-Flexbox-Handbook-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/the-css-flexbox-handbook/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">The CSS Flexbox Handbook – Complete Guide with Practical Examples</a>
      </p><!--kg-card-begin: markdown--><p>Flexbox 是一个有用的工具，用于为网页创建美观且响应式的布局。在本指南中，你将学习像专业人士一样开始使用 CSS Flexbox 所需的一切知识。我们还将学习大量练习示例。</p>
<p>如果你是初学者 web 开发人员，本指南对你来说是一份完美的资源。如果你是经验丰富的开发人员，想要提高响应式网页设计技能，它也会很有用。</p>
<h2 id="">目录</h2>
<ul>
<li><a href="#what-is-flexbox">什么是 Flexbox</a></li>
<li><a href="#what-are-the-benefits-of-using-flexbox">使用 Flexbox 有什么好处</a></li>
<li><a href="#the-main-axis-and-the-cross-axis">主轴和交叉轴</a></li>
<li><a href="#flex-containers-and-flex-items">Flex 容器和 Flex 项</a></li>
<li><a href="#understanding-flex-and-inline-flex">了解 <code>Flex</code> 和 <code>Inline-flex</code></a></li>
<li><a href="#display-flex">display: flex</a></li>
<li><a href="#display-inline-flex">display: inline-flex</a></li>
<li><a href="#the-flex-container-properties">Flex 容器属性</a></li>
<li><a href="#the-flex-direction-property"><code>flex-direction</code> 属性</a></li>
<li><a href="#the-flex-wrap-property"><code>flex-wrap</code> 属性</a></li>
<li><a href="#the-flex-flow-shorthand-property"><code>flex-flow</code> 缩写属性</a></li>
<li><a href="#the-justify-content-property"><code>justify-content</code> 属性</a></li>
<li><a href="#the-align-items-property">T<code>align-items</code> 属性</a></li>
<li><a href="#the-align-content-property"><code>align-content</code> 属性</a></li>
<li><a href="#the-place-content-property"><code>place-content</code> 属性</a></li>
<li><a href="#the-flex-items-properties">Flex 项属性</a></li>
<li><a href="#the-order-property"><code>order</code> 属性</a></li>
<li><a href="#the-align-self-property"><code>align-self</code> 属性</a></li>
<li><a href="#the-flex-grow-property"><code>flex-grow</code> 属性</a></li>
<li><a href="#the-flex-shrink-property"><code>flex-shrink</code> 属性</a></li>
<li><a href="#the-flex-basis-property"><code>flex-basis</code> 属性</a></li>
<li><a href="#the-flex-shorthand-property"><code>flex</code> 缩写属性</a></li>
<li><a href="#flexbox-gaps">Flexbox 间隙</a></li>
<li><a href="#how-to-center-an-element-with-flexbox">如何使用 Flexbox 将元素居中</a></li>
<li><a href="#practice-with-flexbox-games">通过 Flexbox 游戏练习</a></li>
<li><a href="#are-there-bugs-in-css-flexbox">CSS Flexbox 中有 Bug 吗</a></li>
<li><a href="#conclusion">总结</a></li>
</ul>
<h2 id="what-is-flexbox">什么是 Flexbox</h2>
<p>Flexbox 是“Flexible Box Layout”的缩写。它是一个 CSS 布局模型，可以简化复杂布局的创建。它提供了一种灵活的方式来对齐元素并在容器元素内分配空间。</p>
<p>Flexbox 布局模型是双向的。这意味着你可以按行、列或两者排列元素。稍后会详细介绍。</p>
<h3 id="what-are-the-benefits-of-using-flexbox">使用 Flexbox 有什么好处</h3>
<p>在 Flexbox 出现之前，创建复杂的布局和响应式网页非常艰难。你需要 CSS 浮动和位置属性的组合。这需要许多变通方法和技巧。</p>
<p>但使用 Flexbox，你现在可以面对更少的困难，使用更少的代码行数来实现以下操作：</p>
<ul>
<li>使用<code>justify-content</code> 和 <code>align-items</code> 等属性对齐和居中元素。</li>
<li>无需编写大量媒体查询即可开发响应式布局。</li>
<li>在不改变 HTML 结构的情况下重新排序元素。</li>
<li>创建相同高度的列，无需任何额外的 HTML 元素或背景图片。</li>
</ul>
<p>现在，你了解了 Flexbox 是什么，以及可以使用它做的一些事情。让我们看看你如何使用它。</p>
<h3 id="the-main-axis-and-the-cross-axis">主轴和交叉轴</h3>
<p>关于 Flexbox，你首先需要了解的是轴的概念。每个 Flex 容器（ <code>display</code> 属性设置为 <code>flex</code> 或 <code>inline-flex</code> 的元素）都有一个主轴和一个交叉轴。</p>
<p>主轴是水平的还是垂直的，具体取决于 <code>flex-direction</code> 的值。如果你不熟悉 <code>flex-direction</code> , 不用担心。你即将学会它。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/44.-main---cross-axis.png" alt="The main axis and the cross axis when the " width="600" height="400" loading="lazy"></p>
<p><em><code>flex-direction</code> 为 <code>row</code> 时的交叉轴和主轴</em></p>
<p>在这个示例中，主轴是水平的，交叉轴是垂直的。</p>
<p>以下是主轴垂直且交叉轴水平的示例。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/45.-cross---main-axis.png" alt="45.-cross---main-axis" width="600" height="400" loading="lazy"></p>
<p><em><code>flex-direction</code> 为 <code>column</code> 时的主轴和交叉轴</em></p>
<h2 id="flex-containers-and-flex-items">Flex 容器和 Flex 项</h2>
<p>要使用 Flexbox 的所有属性，你需要将元素的 <code>display</code> 属性设置为 <code>flex</code> 或 <code>inline-flex</code>。</p>
<p>这会将元素变成 flex 容器，并且该元素的子元素变成 flex 项。</p>
<p>举个例子:</p>
<pre><code class="language-HTML">&lt;section class="container"&gt;  
	&lt;div&gt;Flex Item 1&lt;/div&gt;  
    &lt;div&gt;Flex Item 2&lt;/div&gt;  
    &lt;div&gt;    
    	&lt;p&gt;This paragraph is not a flex item&lt;/p&gt;  
    &lt;/div&gt;
&lt;/section&gt;
</code></pre>
<pre><code class="language-CSS">.container {  
  display: flex;
}
</code></pre>
<p><code>.container</code> 元素现在是一个 Flex 容器。这三个 <code>div</code> 元素是 <code>.container</code> 元素的直接子元素，这使得它们成为 Flex 项。</p>
<p>但第三个 div 内的段落元素不是 Flex 项。这是因为它不是 <code>.container</code> 元素的直接子元素。</p>
<h2 id="understanding-flex-and-inline-flex">了解 <code>Flex</code> 和 <code>Inline-flex</code></h2>
<p>你可以使用 <code>flex</code> 和 <code>inline-flex</code> 使元素成为 Flex 容器。不同之处在于它们与周围元素的交互方式。</p>
<h3 id="display-flex"><code>display: flex</code></h3>
<p>这使得 Flex 容器的行为类似块级元素。Flex 容器占据其父元素的整个可用宽度。它会在新的一行开始，并且其后的元素也会在新的一行开始。</p>
<p>例如:</p>
<pre><code class="language-HTML">&lt;button&gt;Button One&lt;/button&gt;

/* Flex Container */
&lt;section class="container"&gt;  
	&lt;div id="red"&gt;&lt;/div&gt;  
	&lt;div id="gold"&gt;&lt;/div&gt;  
	&lt;div id="green"&gt;&lt;/div&gt;
&lt;/section&gt;

&lt;button&gt;Button Two&lt;/button&gt;
</code></pre>
<pre><code class="language-CSS">.container {
	display: flex;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/46.-display-flex.png" alt="46.-display-flex" width="600" height="400" loading="lazy"></p>
<p><em>当你使用 <code>display: flex</code> 时，Flex 容器的行为类似于块元素`</em></p>
<p><code>.container</code> 元素占据了主体（其父元素）的整个可用宽度。</p>
<h3 id="display-inline-flex"><code>display: inline-flex</code></h3>
<p>这使得 Flex 容器的行为就像一个内联元素。这允许其他内联元素（如按钮）与其并排。使用前面的示例，这就是当你将 <code>display</code> 从 <code>flex</code> 更改为 <code>inline-flex</code> 时元素的排列方式。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/47.-display-inline-flex.png" alt="47.-display-inline-flex" width="600" height="400" loading="lazy"></p>
<p><em>当你使用 <code>display: inline-flex</code> 时，Flex 容器的行为类似于 <code>inline-elements</code>。</em></p>
<p>Flex 容器不占据其父容器的整个宽度。它仅使用其内容所需的水平空间。</p>
<p><strong>在 StackBlitz 上</strong> <a href="https://stackblitz.com/edit/js-ug2zkz?file=style.css"><strong>练习使用 flex 和 inline-flex</strong></a></p>
<h2 id="the-flex-container-properties">Flex 容器属性</h2>
<p>Flex 容器属性允许你控制 Flex 容器内 Flex 项的布局和对齐方式。</p>
<p><strong>注意:</strong> 你可以将这些属性应用于 Flex 容器，而不是 Flex 项。</p>
<p>以下是 Flex 容器属性:</p>
<ul>
<li><code>flex-direction</code></li>
<li><code>flex-wrap</code></li>
<li><code>flex-flow</code></li>
<li><code>justify-content</code></li>
<li><code>align-items</code></li>
<li><code>align-content</code></li>
<li><code>place-content</code></li>
</ul>
<h3 id="the-flex-direction-property"><code>flex-direction</code> 属性</h3>
<p><code>flex-direction</code> 属性定义了 Flex 项的显示方向。它设置了 Flex 容器的主轴。该属性可以采用以下四个值中的任意一个：</p>
<ul>
<li><code>row</code> (默认值)</li>
<li><code>column</code></li>
<li><code>row-reverse</code></li>
<li><code>column-reverse</code></li>
</ul>
<p>现在，让我们看一些示例，看看它是如何工作的。</p>
<p>在下面的代码片段中，我们有一个名为 <code>names-container</code> 的容器，其中包含四个名字：</p>
<pre><code class="language-HTML">&lt;div class="names-container"&gt;  
	&lt;p id="jill"&gt;1. JILL&lt;/p&gt;  
	&lt;p id="john"&gt;2. JOHN&lt;/p&gt;  
	&lt;p id="jane"&gt;3. JANE&lt;/p&gt;  
	&lt;p id="jack"&gt;4. JACK&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<p>让我们看看使用 <code>flex-direction</code> 属性来排列这些名字的不同方式。</p>
<h4 id="flexdirectionrow"><code>flex-direction: row</code></h4>
<p>这会从左到右水平显示 Flex 项。</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
    flex-direction: row;  
    /* Other styles here... */
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/1.-flex-direction-row.png" alt="1.-flex-direction-row" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>flex-direction: row</code></em></p>
<h4 id="flexdirectioncolumn"><code>flex-direction: column</code></h4>
<p>这会从上到下垂直显示 Flex 项。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/2.-flex-direction-column.png" alt="2.-flex-direction-column" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>flex-direction: column</code></em></p>
<h4 id="flexdirectionrowreverse"><code>flex-direction: row-reverse</code></h4>
<p>这与 row 值相反。它从右到左显示 Flex 项。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/3.-flex-direction-row-reverse.png" alt="3.-flex-direction-row-reverse" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>flex-direction: row-reverse</code></em></p>
<h4 id="flexdirectioncolumnreverse"><code>flex-direction: column-reverse</code></h4>
<p>这与 column 值相反。它从下到上显示 Flex 项。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/4.-flex-direction-column-reverse.png" alt="4.-flex-direction-column-reverse" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>flex-direction: column-reverse</code></em></p>
<p><strong>在 StackBlitz 上</strong> <a href="https://stackblitz.com/edit/js-aaerav?file=style.css"><strong>练习使用 flex-direction</strong></a></p>
<h4 id="">关于反向值和无障碍的注意事项</h4>
<p>当你使用 <code>row-reverse</code> 和 <code>column-reverse</code> 时，有些事情你需要记住。正如你已经看到的，这两个值会影响屏幕上元素的视觉顺序。</p>
<p>但是这些元素在 HTML 中的顺序保持不变，而这些元素在 HTML 中的顺序就是屏幕阅读器和键盘导航控件使用的顺序。</p>
<p>在示例中，当你使用 <code>row-reverse</code> 时，你首先在屏幕上看到 Jack 的名字，然后是 Jane、John 和 Jill。</p>
<p>但是对于使用屏幕阅读器的人来说，他们将会按照 HTML 中的出现顺序而不是屏幕上的顺序来听到这些名字。在这种情况下，他们将首先听到 Jill 的名字，然后是 John、Jane 和 Jack。</p>
<h3 id="the-flex-wrap-property"><code>flex-wrap</code> 属性</h3>
<p>有时，Flex 容器内的空间不足以容纳 Flex 项。</p>
<p>在这种情况下，你可以使用 <code>flex-wrap</code> 属性来选择是让 Flex 项溢出还是另起一行。</p>
<p><code>flex-wrap</code> 属性接受以下任何值：</p>
<ul>
<li><code>nowrap</code> (默认值)</li>
<li><code>wrap</code></li>
<li><code>wrap-reverse</code></li>
</ul>
<p>要看到 <code>flex-wrap</code> 的效果，让我们向 <code>names-container</code> 添加超过四个的名字：</p>
<pre><code class="language-HTML">&lt;div class="names-container"&gt;  
	&lt;p id="jill"&gt;1. JILL&lt;/p&gt;  
	&lt;p id="john"&gt;2. JOHN&lt;/p&gt;  
	&lt;p id="jane"&gt;3. JANE&lt;/p&gt;  
	&lt;p id="jack"&gt;4. JACK&lt;/p&gt;  
	&lt;p id="sara"&gt;5. SARA&lt;/p&gt;  
	&lt;p id="seth"&gt;6. SETH&lt;/p&gt;  
	&lt;p id="seal"&gt;7. SEAL&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<h4 id="flexwrapnowrap"><code>flex-wrap: nowrap</code></h4>
<p>这会使所有的 Flex 项都保持在单行中，无论是在行还是列中。如果在 Flex 容器中没有足够的空间，它允许 Flex 项溢出。请看下面的示例：</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
	flex-direction: row;  
	flex-wrap: nowrap;  
	/* Other styles here... */
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/5.-flex-wrap-nowrap.png" alt="5.-flex-wrap-nowrap" width="600" height="400" loading="lazy"></p>
<p><em>因为 <code>flex-wrap</code> 被设置为 <code>nowrap</code>，所以 Flex 项溢出</em></p>
<p>在这个例子中，由于空间不足，三个名字溢出容器。</p>
<h4 id="flexwrapwrap"><code>flex-wrap: wrap</code></h4>
<p>当空间不足时，这会将 Flex 项换行或推到下一行。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/6.-flex-wrap-wrap.png" alt="6.-flex-wrap-wrap" width="600" height="400" loading="lazy"></p>
<p><em>当 <code>flex-wrap</code> 设置为 <code>wrap</code> 时，Flex 项会换行或移动到下一行</em></p>
<h4 id="flexwrapwrapreverse"><code>flex-wrap: wrap-reverse</code></h4>
<p>这与 <code>wrap</code> 相反。它将溢出的项目移动到下一行，但方向相反。</p>
<p>例如，在名字容器上使用 <code>wrap-reverse</code> 将溢出项移动到下一个顶行，而不是下面的下一行。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/7.-flex-wrap-wrap-reverse.png" alt="7.-flex-wrap-wrap-reverse" width="600" height="400" loading="lazy"></p>
<p><em>示例： <code>flex-wrap: wrap-reverse</code></em></p>
<p><strong>在 StackBlitz 上</strong> <a href="https://stackblitz.com/edit/js-cbmfgr?file=style.css"><strong>练习使用 flex-wrap</strong></a></p>
<h3 id="the-flex-flow-shorthand-property"><code>flex-flow</code> 缩写属性</h3>
<p><code>flex-flow</code> 属性是 <code>flex-direction</code> 和 <code>flex-wrap</code> 属性的缩写。这意味着当你使用 <code>flex-flow</code> 时，只需要一行代码即可同时应用这两个属性。</p>
<p>请参阅下面使用名字容器的示例。你可以为容器指定 <code>flex-direction</code> 和 <code>flex-wrap</code> 属性。</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
	flex-direction: column;  
    flex-wrap: wrap;
}
</code></pre>
<p>或者你可以使用 <code>flex-flow</code> 缩写来获得相同的结果。</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
	flex-flow: column wrap;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/8.-flex-flow.png" alt="8.-flex-flow" width="600" height="400" loading="lazy"></p>
<p><em>示例： <code>flex-flow: column wrap</code></em></p>
<p><strong>在 StackBlitz 上</strong> <a href="https://stackblitz.com/edit/js-xuv4bx?file=style.css"><strong>练习使用 flex-flow</strong></a></p>
<h3 id="the-justify-content-property"><code>justify-content</code> 属性</h3>
<p><code>justify-content</code> 属性处理 Flex 容器主轴上 Flex 项的对齐方式。</p>
<p>你可以使用它来处理主轴上空间的分配方式。该属性可以取以下任何值：</p>
<ul>
<li><code>flex-start</code> (默认值)</li>
<li><code>flex-end</code></li>
<li><code>center</code></li>
<li><code>space-between</code></li>
<li><code>space-around</code></li>
<li><code>space-evenly</code></li>
</ul>
<h4 id="justifycontentflexstart"><code>justify-content: flex-start</code></h4>
<p>这将把 Flex 项放置在 <code>flex-direction</code> 的起始位置。这将把 Flex 项放置在 <code>flex-direction</code> 的起始位置。如果主轴是水平的，并且 <code>flex-direction</code> 的属性值是 <code>row</code>（就像下面的示例），它会将 Flex 项对齐到左侧。如果主轴是垂直的（<code>flex-direction</code> 的属性值是 <code>column</code>），它会将 Flex 项对齐到顶部。</p>
<p>在<code>names-container</code>的例子中，<code>justify-content: flex-start</code> 的效果如下：</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
	justify-content: flex-start;  
	/* Other styles here... */
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/9.-justify-content-flex-start.png" alt="9.-justify-content-flex-start" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>justify-content: flex-start</code></em></p>
<h4 id="justifycontentflexend"><code>justify-content: flex-end</code></h4>
<p>这会将 Flex 项放置在主轴的 flex-direction 的末尾。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/10.-justify-content-flex-end.png" alt="10.-justify-content-flex-end" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>justify-content: flex-end</code></em></p>
<h4 id="justifycontentcenter"><code>justify-content: center</code></h4>
<p>这会将 Flex 项目放置在 Flex 容器主轴的中心。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/11.-justify-content-center-.png" alt="11.-justify-content-center-" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>justify-content: center</code></em></p>
<h4 id="justifycontentspacebetween"><code>justify-content: space-between</code></h4>
<p>这会将第一个 Flex 项放置在主轴的起始位置，并将最后一个项放置在主轴的末尾。然后，主轴上的空间在这些元素之间均匀分布。（校对者注：<code>space-between</code>并不改变元素本身大小，它的作用只是将元素之间的间距均匀划分了）</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/12.-justify-content-space-between.png" alt="12.-justify-content-space-between" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>justify-content: space-between</code></em></p>
<h4 id="justifycontentspaceevenly"><code>justify-content: space-evenly</code></h4>
<p>这会在 Flex 项之间均匀分配空间。这意味着每项前后的空间都相同。（校对者注：<code>space-between</code>模式中，首项和末项在没有其他CSS设置的前提下，与Flex容器的左外边距/右外边距为0，即在Flex容器中与最左端和最右端“顶格”。而<code>space-evenly</code>则是保证每一个Flex项左侧和右侧的边距均是相等的，即Flex项之间的间距和Flex项与Flex容器边界的间距都相等，该模式下Flex项与Flex容器的左右边界也存在间距。）</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/13.-justify-content-space-evenly.png" alt="13.-justify-content-space-evenly" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>justify-content: space-evenly</code></em></p>
<h4 id="justifycontentspacearound"><code>justify-content: space-around</code></h4>
<p>这也会在 Flex 项之间均匀分配空间。这里的关键区别在于，第一个项之前和最后一个项之后的空间是 Flex 项之间空间的一半。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/14.-justify-content-space-around.png" alt="14.-justify-content-space-around" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>justify-content: space-around</code></em></p>
<p><strong>在 StackBlitz 上</strong> <a href="https://stackblitz.com/edit/js-zpcbxv?file=style.css"><strong>练习使用 justify-content</strong></a></p>
<h3 id="the-align-items-property"><code>align-items</code> 属性</h3>
<p><code>align-items</code> 属性处理 Flex 项在 Flex 容器交叉轴上的对齐方式。它可以采用以下任意值：</p>
<ul>
<li><code>stretch</code> (默认值)</li>
<li><code>flex-start</code></li>
<li><code>flex-end</code></li>
<li><code>center</code></li>
<li><code>baseline</code></li>
</ul>
<h4 id="alignitemsstretch"><code>align-items: stretch</code></h4>
<p>这会拉伸 Flex 项以填充 Flex 容器内的空间。</p>
<p>看下面的示例，使用一个新的名字容器（<code>names-container</code>），其中包含不同大小的名字卡片：</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
    align-items: stretch;  
    /* Other styles here... */
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/15.-align-items-stretch.png" alt="15.-align-items-stretch" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>align-items: stretch</code></em></p>
<h4 id="alignitemsflexstart"><code>align-items: flex-start</code></h4>
<p>这会将 Flex 项放置在 Flex 容器的交叉轴的起始位置。如果交叉轴是垂直的，如下例所示， <code>align-items: flex-start</code> 会将项放置在顶部。</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
	align-items: flex-start;  
	/* Other styles here... */
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/16.-align-items-flex-start.png" alt="16.-align-items-flex-start" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>align-items: flex-start</code></em></p>
<h4 id="alignitemsflexend"><code>align-items: flex-end</code></h4>
<p>这会将 Flex 项放置在 Flex 容器的交叉轴的末尾位置。如果交叉轴是垂直的，如下例所示， <code>align-items: flex-end</code> 会将项放置在底部。</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
    align-items: flex-end;  
    /* Other styles here... */
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/17.-align-items-flex-end.png" alt="17.-align-items-flex-end" width="600" height="400" loading="lazy"></p>
<p>示例：<code>align-items: flex-end</code></p>
<h4 id="alignitemscenter"><code>align-items: center</code></h4>
<p>这会将 Flex 项在 Flex 容器的交叉轴的中心对齐。</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
	align-items: center;  
	/* Other styles here... */
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/18.-align-items-center.png" alt="18.-align-items-center" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>align-items: center</code></em></p>
<h4 id="alignitemsbaseline"><code>align-items: baseline</code></h4>
<p>当你使用 <code>baseline</code> 值时，Flex 项目的排列方式是使它们的基线对齐。请参阅下面的示例：</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
	align-items: baseline;  
	/* Other styles here... */
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Untitled-design-1.png" alt="Untitled-design-1" width="600" height="400" loading="lazy"></p>
<p><em>基线用白色虚线表示</em></p>
<p><strong>在 StackBlitz 上</strong> <a href="https://stackblitz.com/edit/js-jydywf?file=style.css"><strong>练习使用 align-items</strong></a></p>
<h3 id="the-align-content-property"><code>align-content</code> 属性</h3>
<p>当你有一个带有换行（或多个 Flex 行）的 Flex 容器时，你可能需要对这些行进行对齐以根据需要分配空间。这时你可以使用 <code>align-content</code> 。该属性可以取以下任何值：</p>
<ul>
<li><code>stretch</code> (默认值)</li>
<li><code>flex-start</code></li>
<li><code>flex-end</code></li>
<li><code>center</code></li>
<li><code>space-between</code></li>
<li><code>space-evenly</code></li>
<li><code>space-around</code></li>
</ul>
<p>在下面的示例中，<code>names-container</code>中有 11 个名字，并且<code>names-container</code>的 <code>flex-wrap</code> 值为 <code>wrap</code>。这意味着你可以应用 <code>align-content</code> 属性来改变 Flex 行的对齐方式。</p>
<h4 id="aligncontentstretch"><code>align-content: stretch</code></h4>
<p>这会拉伸 Flex 行以填充 Flex 容器交叉轴内的空间。</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
	flex-wrap: wrap;  
	align-items: stretch;  
	/* Other styles here... */
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/20.-align-content-stretch.png" alt="20.-align-content-stretch" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>align-content: stretch</code></em></p>
<h4 id="aligncontentflexstart"><code>align-content: flex-start</code></h4>
<p>这将把 Flex 行放置在容器的交叉轴起始位置。例如，如果交叉轴像 <code>names-container</code> 一样是垂直的，它就会将 Flex 行放置在顶部。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/21.-align-content-flex-start.png" alt="21.-align-content-flex-start" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>align-content: flex-start</code></em></p>
<h4 id="aligncontentflexend"><code>align-content: flex-end</code></h4>
<p>这会将 Flex 行放置在容器的交叉轴末尾位置。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/22.-align-content-flex-end.png" alt="22.-align-content-flex-end" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>align-content: flex-end</code></em></p>
<h4 id="aligncontentcenter"><code>align-content: center</code></h4>
<p>这会将 Flex 行放置在容器的交叉轴中心位置。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/23.-align-content-center.png" alt="23.-align-content-center" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>align-content: center</code></em></p>
<h4 id="aligncontentspacebetween"><code>align-content: space-between</code></h4>
<p>这会将第一行放置在交叉轴的起始位置。它还会将最后一行放置在交叉轴的末尾位置。然后，交叉轴上的空间会均匀分配给这些行。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/24.-align-content-space-between.png" alt="24.-align-content-space-between" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>align-content: space-between</code></em></p>
<h4 id="aligncontentspaceevenly"><code>align-content: space-evenly</code></h4>
<p>这会在 Flex 行之间均匀分配空间。这意味着每行前后的空间都是相同的。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/25.-align-content-space-evenly.png" alt="25.-align-content-space-evenly" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>align-content: space-evenly</code></em></p>
<h4 id="aligncontentspacearound"><code>align-content: space-around</code></h4>
<p>这也会在 Flex 行之间均匀分配空间。这里的主要区别在于，第一行之前和最后一行之后的空间是 Flex 行之间空间的一半。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/26.-align-content-space-around.png" alt="26.-align-content-space-around" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>align-content: space-around</code></em></p>
<p><strong>在 StackBlitz 上</strong> <a href="https://stackblitz.com/edit/js-fukvgd?file=style.css"><strong>练习使用 align-content</strong></a></p>
<h3 id="the-place-content-property"><code>place-content</code> 属性</h3>
<p>如果你需要同时使用 <code>justify-content</code> 和 <code>align-content</code> 属性，你可以使用 <code>place-content</code> 缩写属性。</p>
<p>它可以接受一个或两个值。当你给它一个单一值时，浏览器会为 <code>justify-content</code> 和 <code>align-content</code> 应用相同的值。</p>
<p>当你为 <code>place-content</code> 提供两个值时，第一个值将用于 <code>align-content</code> ，第二个值将用于 <code>justify-content</code>。</p>
<p>让我们看一个示例:</p>
<p>无需这样写:</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
	flex-wrap: wrap;  
	align-content: flex-end;  
	justify-content: flex-start;  
	/* Other content */
}
</code></pre>
<p>你可以改为写下面的代码，效果相同：</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
	flex-wrap: wrap;  
	place-content: flex-end flex-start;  
	/* Other content */
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/43.-place-content.png" alt="43.-place-content" width="600" height="400" loading="lazy"></p>
<p><em>示例：使用 <code>place-content</code> 缩写</em></p>
<p><strong>在 StackBlitz 上</strong> <a href="https://stackblitz.com/edit/js-ytdywl?file=style.css"><strong>练习使用 place-content</strong></a></p>
<h2 id="the-flex-items-properties">Flex 项属性</h2>
<p>Flex 容器的每个直接子元素都是 Flex 项。到目前为止，你已经学习了 Flex 容器的属性。</p>
<p>Flexbox 还有一些属性，你可以应用到单个 Flex 项上。它们包括以下内容：</p>
<ul>
<li><code>order</code></li>
<li><code>align-self</code></li>
<li><code>flex-grow</code></li>
<li><code>flex-shrink</code></li>
<li><code>flex-basis</code></li>
<li><code>flex</code></li>
</ul>
<h3 id="the-order-property"><code>order</code> 属性</h3>
<p><code>order</code> 属性确定 Flex 项的出现顺序。</p>
<p>你给这个属性的赋值必须是一个数字。一个数字较小的 Flex 项将出现在数字较大的 Flex 项之前。</p>
<p>在 HTML 代码中，四个名字的顺序如下:</p>
<ol>
<li>Jill</li>
<li>John</li>
<li>Jane</li>
<li>Jack</li>
</ol>
<pre><code class="language-CSS">&lt;div class="names-container"&gt;
	&lt;p id="jill"&gt;1. JILL&lt;/p&gt;
	&lt;p id="john"&gt;2. JOHN&lt;/p&gt;
	&lt;p id="jane"&gt;3. JANE&lt;/p&gt;
	&lt;p id="jack"&gt;4. JACK&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<p>你可以使用 <code>order</code> 属性改变屏幕上的出现顺序。请参阅下面的示例。</p>
<p>以下是没有 <code>order</code> 属性时它们的显示方式:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/27.-no-order-property.png" alt="27.-no-order-property" width="600" height="400" loading="lazy"></p>
<p><em>添加 <code>order</code> 属性之前的名字卡片</em></p>
<p>现在，当你添加以下 <code>order</code> 属性时，它们的显示方式如下所示：</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;
}

#jill {  
	order: 2;  
    background-color: #fe4f46;
}

#john {  
	order: 4;  
    background-color: #fcd65c;
}

#jane {  
	order: 1;  
    background-color: 
    #00bab4;
}

#jack {  
	order: 3;  
    background-color: #003f54;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/28.-with-order-property.png" alt="28.-with-order-property" width="600" height="400" loading="lazy"></p>
<p><em><code>order</code> 属性改变了出现顺序</em></p>
<p><strong>在 StackBlitz 上</strong> <a href="https://stackblitz.com/edit/js-c5mf8q?file=style.css"><strong>练习使用 order 属性</strong></a></p>
<p><strong>警告:</strong> 尽管屏幕上的出现顺序改变了，但 HTML 中的顺序保持不变。而屏幕阅读器使用的是 HTML 中的顺序。如果可能，最佳实践是在 HTML 中改变顺序，而不是使用 Flexbox 进行更改。</p>
<h3 id="the-align-self-property"><code>align-self</code> 属性</h3>
<p>你可以使用 <code>align-self</code> 属性为一个 Flex 项单独设置不同的对齐方式。</p>
<p>它的工作方式与 <code>align-items</code> 属性相同。不同之处在于， <code>align-items</code> 适用于所有 Flex 项，而 <code>align-self</code> 属性仅适用于特定项。</p>
<p>例如:</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
    align-items: center;  
    /* Other styles */    
}

#jill {
	align-self: flex-start;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/37.-align-self.png" alt="37.-align-self" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>align-self</code> 带有 <code>flex-start</code> 值</em></p>
<p>在这个示例中，<code>names-container</code> 的 <code>align-items</code> 属性设置为 <code>center</code>，这会使所有名字都居中对齐。</p>
<p>但是使用 <code>align-self</code> 属性，你可以用 <code>flex-start</code> 将 Jill 的名字卡片对齐到顶部。</p>
<p><strong>在 StackBlitz 上</strong> <a href="https://stackblitz.com/edit/js-e9ctpu?file=style.css"><strong>练习使用 align-self 属性</strong></a></p>
<h3 id="the-flex-grow-property"><code>flex-grow</code> 属性</h3>
<p>当你将容器的 <code>display</code> 设置为 <code>flex</code> 时，通常会在排列项之后有一些额外的空间。请参阅下面的示例：</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
    justify-content: 
    flex-start;  
 	/* Other styles */
 }
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/29.-flex-grow-extra-space.png" alt="29.-flex-grow-extra-space" width="600" height="400" loading="lazy"></p>
<p><em>Flex 容器有足够的空间容纳 Flex 项</em></p>
<p>浏览器会将多余的空间视为 <code>1</code> 的值。这意味着当你为其中一个 Flex 项的 <code>flex-grow</code> 设置为 <code>0.5</code> 时，浏览器会将剩余空间的一半添加到该项的大小中。</p>
<pre><code class="language-CSS">#jill {
	flex-grow: 0.5;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/30.-flex-grow-0.5.png" alt="30.-flex-grow-0.5" width="600" height="400" loading="lazy"></p>
<p><em><code>flex-grow</code> 属性使 Jill 的大小大于其初始大小</em></p>
<p>如果你给 <strong>仅一个 Flex 项</strong> 设置了 <code>flex-grow</code> 值为 <code>1</code> ，浏览器将把所有额外的空间都分配给该项。</p>
<p><strong>注意：</strong> 如果容器中只有一个项具有 <code>flex-grow</code> 值，则任何值为 1 或更大的值都会使其占据所有额外空间。</p>
<p>例如，下面两个代码片段对 Jill 的卡片具有相同的效果：</p>
<pre><code class="language-CSS">#jill {  
	flex-grow: 1;
}
</code></pre>
<pre><code class="language-CSS">#jill {  
	flex-grow: 99;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/31.-flex-grow-1-or-more.png" alt="31.-flex-grow-1-or-more" width="600" height="400" loading="lazy"></p>
<p><em>当容器中只有一个卡片的 <code>flex-grow</code> 为 <code>1</code> 或以上时</em></p>
<p>当你为多个元素添加 <code>flex-grow</code> 值会发生什么？</p>
<p>浏览器将按比例为它们共享额外的空间。</p>
<p>例如，当你给 Jane 设置 <code>flex-grow</code> 为 <code>3</code>，给 Jack 设置 <code>flex-grow</code> 为 <code>1</code> 时，浏览器将以 <code>3:1</code> 的比例分享额外的空间。</p>
<p>这意味着额外空间的总值变为 <code>4</code>（3+1）。<code>Jane</code> 将获得额外空间的 <code>3/4</code>，而 <code>Jack</code> 将获得 <code>1/4</code>。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/32.-flex-grow-jane-jack.png" alt="32.-flex-grow-jane-jack" width="600" height="400" loading="lazy"></p>
<p><em>额外的空间按比例在 <code>Jane</code> 和 <code>Jack</code> 之间共享</em></p>
<p><strong>在 StackBlitz 上</strong> <a href="https://stackblitz.com/edit/js-m6h8af?file=style.css"><strong>练习使用 flex-grow 属性</strong></a></p>
<h3 id="the-flex-shrink-property"><code>flex-shrink</code> 属性</h3>
<p><code>flex-shrink</code> 属性与 <code>flex-grow</code> 相反。</p>
<p>当你希望在存在额外空间时增加 Flex 项的大小时，你可以使用 <code>flex-grow</code>。但是，当 Flex 容器中的空间不足时，你可以使用 <code>flex-shrink</code> 来减小 Flex 项的大小。</p>
<p>请参阅下面的示例:</p>
<pre><code class="language-HTML">&lt;div class="numbers-container"&gt;
	&lt;p id="one"&gt;1&lt;/p&gt;
	&lt;p id="two"&gt;2&lt;/p&gt;
	&lt;p id="three"&gt;3&lt;/p&gt;
	&lt;p id="four"&gt;4&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<pre><code class="language-CSS">.numbers-container {  
	display: flex;  
	justify-content: flex-start;  
	/* Other styles */
}

#one {  
	flex-shrink: 2;  
	background-color: #fe4f46;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/33.-flex-shrink-value-2.png" alt="33.-flex-shrink-value-2" width="600" height="400" loading="lazy"></p>
<p><em>第一张卡片缩小，为其他卡片腾出空间</em></p>
<p>在这个示例中，四个数字每个的宽度都设置为 150px（总共 600px）。但 <code>numbers-container</code> 的宽度只有 400px，这是不够的。</p>
<p>卡片必须缩小以适应可用空间。但是 flex-shrink 的值为 <code>2</code> 的数字 <code>1</code> ，元素大小缩小到了其他数字的 1/2。</p>
<h4 id="flex">如果你不希望一个 Flex 项缩小怎么办？</h4>
<p>为了防止 Flex 项收缩，给它一个 <code>flex-shrink</code> 值为 <code>0</code>。</p>
<p>例如，当你为 Number <code>1</code> 指定 <code>flex-shrink</code> 为 <code>0</code> 时，它将保持 150px 的宽度。其他 Flex 项将缩小以适应剩余空间。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/34.-flex-shrink-vallue-0.png" alt="34.-flex-shrink-vallue-0" width="600" height="400" loading="lazy"></p>
<p>第一个卡片不会缩小，因为它的 <code>flex-shrink</code> 值为 <code>0</code>。</p>
<p><strong>在 StackBlitz 上</strong> <a href="https://stackblitz.com/edit/js-q9zndc?file=style.css"><strong>练习使用 flex-shrink 属性</strong></a></p>
<h3 id="the-flex-basis-property"><code>flex-basis</code> 属性</h3>
<p>你可以使用 <code>flex-basis</code> 属性来设置特定 Flex 项的默认长度。这取决于 <code>flex-direction</code> ，可以是宽度或高度。</p>
<p>如果 <code>flex-direction</code> 是 <code>row</code> 或 <code>row-reverse</code> ，则 <code>flex-basis</code> 的值就成为 Flex 项的初始宽度。</p>
<p>如果 <code>flex-direction</code> 是 <code>column</code> 或 <code>column-reverse</code> ，那么 <code>flex-basis</code> 的值就成为 Flex 项的初始高度。</p>
<p>例如:</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
	flex-direction: column;  
	/* Other styles */
}

div {  
	height: 20px;
}

#jane {  
	flex-basis: 60px;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/35.-flex-basis-height.png" alt="35.-flex-basis-height" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>flex-basis</code> 设置 item 的高度</em></p>
<p>在这个示例中，div 的高度设置为 20px。但 Jane 得到的 <code>flex-basis</code> 值为 60px。这会覆盖所有 div 的 20px。</p>
<p>注意：Jane 的 <code>flex-basis</code> 值为 60px，因为 <code>flex direction</code> 是 <code>column</code>。这意味着主轴是垂直的。</p>
<p>下面是另一个示例。这次，<code>flex-direction</code> 是 <code>row</code>。这意味着 <code>flex-basis</code> 将设置 Flex 项的宽度。</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
	flex-direction: row;  
    /* Other styles */
}

div {  
	width: 70px;
}

#jane {  
	flex-basis: 140px;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/36.-flex-basis-width.png" alt="36.-flex-basis-width" width="600" height="400" loading="lazy"></p>
<p><em>示例：<code>flex-basis</code> 设置 item 的宽度</em></p>
<p>虽然所有其他 div 的宽度均为 70px，但 Jane 的宽度由 <code>flex-basis</code> 设置为 140px。</p>
<p><strong>在 StackBlitz 上</strong> <a href="https://stackblitz.com/edit/js-maihzd?file=style.css"><strong>练习使用 flex-basis 属性</strong></a></p>
<h3 id="the-flex-shorthand-property"><code>flex</code> 缩写属性</h3>
<p>你可以使用 <code>flex</code> 作为 <code>flex-grow</code>、<code>flex-shrink</code> 和 <code>flex-basis</code> 属性的缩写。</p>
<p>例如，无需这样写：</p>
<pre><code class="language-CSS">.flex-item {  
	flex-grow: 2;  
	flex-shrink: 0;  
	flex-basis: 50px;
}
</code></pre>
<p>你可以像这样使用缩写，它会产生相同的效果：</p>
<pre><code class="language-CSS">.flex-item {  
	flex: 2 0 50px;
}
</code></pre>
<p><code>flex</code> 属性最多可以接受三个值。值的顺序很重要。浏览器将第一个值分配给 <code>flex-grow</code>，第二个值分配给 <code>flex-shrink</code>，第三个值分配给 <code>flex-basis</code>。</p>
<p><code>flex</code> 的默认值是 <code>1 0 auto</code>。</p>
<p>这意味着如果你给 <code>flex</code> 一个值为 2，浏览器将使用 2 作为 <code>flex-grow</code>。然后它将 <code>flex-shrink</code> 设置为 0，将<code>flex-basis</code> 设置为 auto。</p>
<p><strong>在 StackBlitz 上</strong> <a href="https://stackblitz.com/edit/js-m19hov?file=style.css"><strong>练习使用 <code>flex</code> 属性</strong></a></p>
<h2 id="how-to-center-an-element-with-flexbox">如何使用 Flexbox 将元素居中</h2>
<p>让许多前端开发人员头疼的问题之一是元素居中。 Flexbox 对此提供了一个完美的解决方案。</p>
<p>涉及两个步骤：</p>
<ol>
<li>通过将 <code>display</code> 设置为 <code>flex</code> 使父元素成为 Flex 容器。</li>
<li>将 <code>justify-content</code> 和 <code>align-items</code> 都设置为 <code>center</code>。</li>
</ol>
<p>就是这样！你的元素将完美居中！</p>
<p>例如:</p>
<pre><code class="language-HTML">&lt;div class="name-container"&gt;  
	&lt;p&gt;JOHN&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<pre><code class="language-CSS">.name-container {  
	display: flex;  
	justify-content: center;  
	align-items: center;  
	/* Other Styles */
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/38.-center-element-w--flexbox.png" alt="38.-center-element-w--flexbox" width="600" height="400" loading="lazy"></p>
<p><em>示例：使用 Flexbox 居中一个元素</em></p>
<p>无论你是试着居中文本、图像，还是整个导航栏，这都能完美运行。</p>
<h2 id="flexbox-gaps">Flexbox 间隙</h2>
<p>你可以使用 <code>gap</code> 属性来调整 flex 项之间的间距。</p>
<p><strong>注意：</strong> 你将 gap 属性应用于 Flex 容器，而不是 Flex 项。</p>
<p><code>gap</code> 可以取两个值：第一个值用于行之间的间距，第二个值用于列之间的间距。</p>
<p>例如:</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
	flex-wrap: wrap;  
	gap: 50px 10px; 
	/* row-gap column-gap */
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/39.-gap-two-values.png" alt="39.-gap-two-values" width="600" height="400" loading="lazy"></p>
<p><em>示例：为 gap 属性指定两个值</em></p>
<p>如果你想要的行和列之间的间距相同，你可以使用单个值。浏览器将为行和列都应用相同的值。</p>
<p>例如:</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
	flex-wrap: wrap;  
	gap: 10px; 
	/* Other Styles */
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/40.-gap-single-value.png" alt="40.-gap-single-value" width="600" height="400" loading="lazy"></p>
<p><em>示例：行距和列距仅使用一个值</em></p>
<p>如果你需要仅在行之间应用特定的间隙值，你还可以使用属性 <code>row-gap</code> 。如果你需要仅在列之间添加间隙，则使用 <code>column-gap</code> 。</p>
<p>例如：仅在行之间添加间距：</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
	flex-wrap: wrap;  
	row-gap: 20px; 
	/* Other Styles */
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/41.-row-gap.png" alt="41.-row-gap" width="600" height="400" loading="lazy"></p>
<p><em>示例：使用 <code>row-gap</code></em></p>
<p>例如: 仅在列之间添加间距：</p>
<pre><code class="language-CSS">.names-container {  
	display: flex;  
	flex-wrap: wrap;  
	column-gap: 20px; 
	/* Other Styles */
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/42.-column-gap.png" alt="42.-column-gap" width="600" height="400" loading="lazy"></p>
<p><em>示例：使用 <code>column-gap</code></em></p>
<p><strong>在 StackBlitz 上</strong> <a href="https://stackblitz.com/edit/js-v77toh?file=style.css"><strong>练习使用 gap 属性</strong></a></p>
<h2 id="practice-with-flexbox-games">通过 Flexbox 游戏练习</h2>
<p>想要以交互方式练习 Flexbox？看看以下游戏。它们以有趣且引人入胜的方式提供亲身体验 Flexbox 的实践练习。</p>
<ul>
<li><a href="https://flexboxfroggy.com/">Flexbox Froggy</a></li>
<li><a href="http://www.flexboxdefense.com/">Flexbox Defense</a></li>
<li><a href="https://mastery.games/flexboxzombies/">Flexbox Zombies</a></li>
</ul>
<h2 id="are-there-bugs-in-css-flexbox">CSS Flexbox 中有 Bug 吗</h2>
<p>虽然 CSS Flexbox 是一个强大的布局工具，但它有一些可能会让你感到意外的 bug 。</p>
<p>一个常见的例子是 <strong>某些 HTML 元素无法充当 flex 容器</strong>。这些元素包括 <code>&lt;button&gt;</code>、<code>&lt;fieldset&gt;</code> 和 <code>&lt;summary&gt;</code> 元素。</p>
<p>解决方法是使用像 <code>div</code> 这样的元素来包裹该元素的子元素。然后在包装器 <code>div</code> 上使用 Flexbox。</p>
<p>如果你对其他 Flexbox 的 bug 和解决方法感兴趣，可以查看 GitHub 上的 <a href="https://github.com/philipwalton/flexbugs">Flexbugs 仓库</a>。</p>
<h2 id="conclusion">总结</h2>
<p>在本指南中，你学习了所有 Flexbox 属性、它们的值以及如何使用它们创建响应式布局。你还了解了一些像 Flexbox Froggy 这样的游戏，可以用来练习。</p>
<p>感谢你阅读本文，祝你编码愉快！欢迎<a href="https://www.youtube.com/@DevAfterHours">订阅我的 YouTube 频道</a>以获取更深入的教程。</p>
<p><strong>译文校对者：<a href="https://www.freecodecamp.org/chinese/news/author/tsukistar/">Tsukistar</a></strong></p>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 网页布局 - 如何使用 CSS 中的 Grid 和 Flex 创建响应式网页 ]]>
                </title>
                <description>
                    <![CDATA[ 你网页的布局对于你的网站就像建筑物的平面图一样重要。没有它们你只是在空中建造城堡。 当你要创建或设计一个网站或应用时，首先要做的是决定布局。这很重要，因为在这个布局中，你可以指定元素的排列方式，以便以预期的方式和层级对它们进行评估。 基本上，每个网页布局的目标是减少混乱，增强可用性，并最终为用户提供愉快的体验。布局的一些主要元素包括导航、菜单和内容。 在网页和前端开发中，在开始构建之前先确定一个布局可以帮助你决定使用哪个CSS布局模块：Flexbox还是Grid。 在本文中，我们将学习这些工具的具体含义，并通过构建一个简单而美观的登录页面来了解它们的最佳使用方式。 我们将要构建的内容 登录页设计请在Codepen上查看这个项目 [https://codepen.io/ophyboamah/pen/KKRLoJr]。 项目的功能性  1. 网页布局：创建一个美观的登录页面  2. 移动设备响应式设计 前置准备  * 掌握基本的HTML和CSS的基本知识  * 一个像VS Code这样的集成开发环境（文本编辑器）  * 一个网络浏览器（Chrome、FireFox） 步骤  ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/web-layouts-use-css-grid-and-flex-to-create-responsive-webpages/</link>
                <guid isPermaLink="false">6575bb645c9dcf03f9984d32</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp.org ]]>
                </dc:creator>
                <pubDate>Thu, 07 Dec 2023 13:30:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2023/12/WebLayouts-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/web-layouts-use-css-grid-and-flex-to-create-responsive-webpages/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Web Layouts – How to Use CSS Grid and Flex to Create a Responsive Web Page</a>
      </p><!--kg-card-begin: markdown--><p>你网页的布局对于你的网站就像建筑物的平面图一样重要。没有它们你只是在空中建造城堡。</p>
<p>当你要创建或设计一个网站或应用时，首先要做的是决定布局。这很重要，因为在这个布局中，你可以指定元素的排列方式，以便以预期的方式和层级对它们进行评估。</p>
<p>基本上，每个网页布局的目标是减少混乱，增强可用性，并最终为用户提供愉快的体验。布局的一些主要元素包括导航、菜单和内容。</p>
<p>在网页和前端开发中，在开始构建之前先确定一个布局可以帮助你决定使用哪个CSS布局模块：<code>Flexbox</code>还是<code>Grid</code>。</p>
<p>在本文中，我们将学习这些工具的具体含义，并通过构建一个简单而美观的登录页面来了解它们的最佳使用方式。</p>
<h2 id="">我们将要构建的内容</h2>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/10/homepage-2.png" alt="登录页设计" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>登录页设计</figcaption>
</figure>
<p>请在Codepen上查看<a href="https://codepen.io/ophyboamah/pen/KKRLoJr">这个项目</a>。</p>
<h2 id="">项目的功能性</h2>
<ol>
<li>网页布局：创建一个美观的登录页面</li>
<li>移动设备响应式设计</li>
</ol>
<h2 id="">前置准备</h2>
<ul>
<li>掌握基本的HTML和CSS的基本知识</li>
<li>一个像VS Code这样的集成开发环境（文本编辑器）</li>
<li>一个网络浏览器（Chrome、FireFox）</li>
</ul>
<h2 id="">步骤</h2>
<ol>
<li>为您的项目创建一个文件夹，并在集成开发环境中打开它。</li>
<li>在您的项目文件夹中创建 index.html 和 style.css 文件。</li>
<li>创建一个用于存储图像的 assets 文件夹。</li>
<li>在 index.html 文件中，创建HTML的基本结构，并在 <code>&lt;head&gt;</code> 标签内链接您的 CSS 文件和字体 URL。</li>
</ol>
<h2 id="">资源</h2>
<ol>
<li><strong>字体:</strong> <a href="https://fonts.googleapis.com/css2?family=Epilogue:wght@500;700&amp;family=Poppins:wght@400;500;700&amp;display=swap">https://fonts.googleapis.com/css2?family=Epilogue:wght@500;700&amp;family=Poppins:wght@400;500;700&amp;display=swap</a></li>
<li><strong>桌面图像:</strong> <a href="https://i.postimg.cc/0Nt97Bhf/image-hero-desktop.png">https://i.postimg.cc/0Nt97Bhf/image-hero-desktop.png</a></li>
<li><strong>移动设备图像:</strong> <a href="https://i.postimg.cc/ZnYfhwwW/image-hero-mobile.png">https://i.postimg.cc/ZnYfhwwW/image-hero-mobile.png</a></li>
<li><strong>客户 Logo (Databiz):</strong> <a href="https://i.postimg.cc/gJ9Y84m6/client-databiz.png">https://i.postimg.cc/gJ9Y84m6/client-databiz.png</a></li>
<li><strong>客户 Logo (Audiophile):</strong> <a href="https://i.postimg.cc/15DDqYSD/client-audiophile.png">https://i.postimg.cc/15DDqYSD/client-audiophile.png</a></li>
<li><strong>客户 Logo (Meet):</strong> <a href="https://i.postimg.cc/5ybQqfbv/client-meet.png">https://i.postimg.cc/5ybQqfbv/client-meet.png</a></li>
<li><strong>客户 Logo (Maker):</strong> <a href="https://i.postimg.cc/g2NsxByN/client-maker.png">https://i.postimg.cc/g2NsxByN/client-maker.png</a></li>
</ol>
<h1 id="flexbox">如何使用 Flexbox</h1>
<p>通常情况下，HTML 元素根据其默认的显示样式进行对齐。 这意味着，在没有使用 CSS 进行外部样式设置的情况下，块级元素如 <code>p</code> 和 <code>div</code> 会在新行上开始。而行内元素如 <code>input</code> 和 <code>span</code> 则会在同一行上并排显示。</p>
<p>然而，Flexbox 的概念允许您轻松地将这些元素在水平或垂直方向上放置，通常称为一维布局。为了实现这一点，至少需要两个元素：<strong>弹性容器</strong>（flex container）和<strong>弹性子元素</strong>（flex item）。分别代表父元素和子元素。</p>
<p>在响应式设计中，Flexbox 的目的是允许容器及其子元素填充定义的空间或根据设备的尺寸进行收缩。</p>
<h2 id="">弹性盒子的方向和轴线</h2>
<p>flex-direction 是 CSS Flexbox 的一个重要属性，因为它决定了弹性子元素的排列方向。它通过指定弹性容器的主轴来实现这一点。</p>
<p>有两个主要的轴线，叫<code>主轴</code>和<code>交叉轴</code>，主轴是指弹性子元素在弹性容器中排列的方向，而交叉轴始终是主轴的对立面轴线。</p>
<p>尝试使用数学中的 x 轴和 y 轴的概念来理解 Flexbox 可能会有一些问题。这主要是因为在 Flexbox 中，主轴可以是垂直或水平的，具体取决于 flex-direction 的值。</p>
<p>flex-direction 属性接受的值包括 row（默认值）、row-reverse、column 和 column-reverse。在本项目中，我们将关注 row 和 column。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/10/flexdirection.png" alt="flex-direction: row" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>flex-direction: row</figcaption>
</figure>
<p>当 flex-direction 属性的值为 row 时，主轴是水平的，交叉轴是垂直的，如上图所示。这意味着弹性子元素将水平排列。</p>
<p>由于 row 是默认值，如果将容器设置为 flex，但未指定 flex-direction，则弹性子元素将自动排列为一行。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/10/flexdirectioncolumn.png" alt="flex-direction: column" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>flex-direction: column</figcaption>
</figure>
<p>当 flex-direction 属性的值为 column 时，主轴是垂直的，交叉轴是水平的，如上图所示。这意味着弹性项目将垂直排列。</p>
<h2 id="">如何构建导航栏</h2>
<p>既然我们了解了 Flexbox 的工作原理，让我们开始构建我们的导航栏。首先，我们将提供其中的内容，即菜单项和Logo。我们将为它们提供描述性的类，以便在 CSS 文件中轻松引用它们。</p>
<pre><code class="language-HTML">&lt;nav&gt;
      &lt;h2 class="logo"&gt;snap&lt;/h2&gt;
      &lt;ul class="menu-items"&gt;
        &lt;li&gt;Features&lt;/li&gt;
        &lt;li&gt;Company&lt;/li&gt;
        &lt;li&gt;Careers&lt;/li&gt;
        &lt;li&gt;About&lt;/li&gt;
      &lt;/ul&gt;
      &lt;ul class="cta-btns"&gt;
        &lt;li&gt;Login&lt;/li&gt;
        &lt;li&gt;Register&lt;/li&gt;
      &lt;/ul&gt;
&lt;/nav&gt;
</code></pre>
<p>下面的图片是上述代码的输出结果。因为 <code>&lt;ul&gt;</code> 和 <code>&lt;li&gt;</code> 都是块级元素，所以其中指定的每个项目都将显示在新的一行上。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/preflexx-1.png" alt="preflexx-1" width="600" height="400" loading="lazy"></p>
<p>Flexbox 布局的显示属性是在父容器上声明的，并影响子元素。这意味着如果你有一个杂货清单的无序列表，无法直接在这种情况下将 display: flex 应用于 <code>&lt;li&gt;</code>，因为它们是子元素。相反，要将它们显示为 flex 布局，你需要首先创建一个父容器，并将其应用于该容器。</p>
<p>在下面的 CSS 代码中，我们定义了项目的字体样式和大小，以及导航栏Logo的样式。我们还将导航栏元素及其内部的一些元素设置为 flex 布局。</p>
<pre><code class="language-CSS">* {
  font-family: "Epilogue", sans-serif;
  font-size: 0.85rem;
}

.logo {
  font-size: 1.3rem;
}

nav,
.cta-btns,
.menu-items {
  display: flex;
}
</code></pre>
<p>导航栏初始化样式</p>
<p>下面的图片是上述代码的输出结果。元素已经以 flex 方式显示。然而，由于我们没有指定 flex-direction，它们会自动排列成一行。</p>
<p>但是，正如你在下面使用标尺（红线）看到的那样，flex 子元素的对齐并不如预期。让我们通过学习另一个重要的 flex 元素来修复这个问题。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/displayflex.png" alt="displayflex" width="600" height="400" loading="lazy"></p>
<h3 id="alignitems">如何使用 <code>align-items</code> 属性</h3>
<p>这是一个控制 flex 子元素在交叉轴上排列的 Flexbox 属性。它接受的值有 flex-start、flex-end 和 center，具体取决于元素的对齐需求。下面的图片展示了每个值的工作方式。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/align-items-1.png" alt="align-items-1" width="600" height="400" loading="lazy"></p>
<p>从上面的图片可以看出，如果我们希望确保 <code>&lt;nav&gt;</code> 内的 flex 子元素正确对齐，我们必须在该元素上添加 align-items 属性，并将其值设为 center。因此，我们需要在我们的 flex 容器上添加一个 <em>align-items</em> 属性，并将其值设为 <em>center</em>，如下所示的 CSS 代码：</p>
<pre><code class="language-CSS">nav,
.cta-btns,
.menu-items {
  display: flex;
  align-items: center;
}
</code></pre>
<p>导航栏的对齐方式</p>
<p>如你可以在下面的图片中看到，flex 子元素现在已经按照预期对齐了。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/aligncenter.png" alt="aligncenter" width="600" height="400" loading="lazy"></p>
<p>但是再次出现了一些问题。我们希望在导航栏上正确地将项目展开：将 Logo 放在极左边，登录和注册放在极右边，其余项目放在中间。</p>
<p>我们可以使用 <code>justify-content</code> 属性来实现这一点。让我们接下来学习一下它，然后再进行实现。</p>
<h3 id="justifycontent">如何使用 <code>justify-content</code> 属性</h3>
<p>这是一个控制 flex 子元素在主轴上排列的 Flexbox 属性。它还定义了浏览器如何在 flex 容器内在 flex 项目之间分配空间，以及在 flex 项目周围分配空间。</p>
<p>为了实现响应式布局，justify-content 属性有助于分配剩余的多余空间，即在 flex 子元素排列完成后剩下的空间。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/10/justifycontentstyles.png" alt="justify-content 样式" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>justify-content 样式</figcaption>
</figure>
<p>从与 justify-content 属性的各个值相关联的样式中，我们可以看到底部两个值更接近我们想要实现的效果。</p>
<p>我们可以选择使用 space-around 或 space-between，并在两侧添加一些内边距来将子元素推离边缘。我们还可以将 list-style 属性的值设为 none，以去除列表项前面的点。</p>
<pre><code class="language-CSS">li {
  list-style: none;
}

nav {
  justify-content: space-between;
}
</code></pre>
<p>导航栏的 justify-content</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/10/justifycontent-2.png" alt="justify-content 导航栏输出效果" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>justify-content 导航栏输出效果</figcaption>
</figure>
<p>现在我们已经将子元素放置在所需的位置上，我们需要在它们之间创建一些小的间距。在这种情况下，我们将给每个列表项设置 margin-right: 1rem。我们还设置其他样式，例如字体大小、颜色以及为注册项设置边框。</p>
<pre><code class="language-CSS">nav {
  margin: 0 1.5rem 1.5rem 1.5rem;
  justify-content: space-between;
}

.logos-section {
  display: flex;
}

.menu-items li,
.cta-btns li {
  font-size: 0.7rem;
  margin-right: 1rem;
  color: hsl(0, 0%, 41%);
}

.cta-btns li:nth-last-child(1) {
  border: 1px solid gray;
  padding: 0.2rem 0.7rem;
  border-radius: 0.3rem;
}
</code></pre>
<p>完整的导航栏设计</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/10/justifyandstyles-1.png" alt="带有样式的导航栏" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>带有样式的导航栏</figcaption>
</figure>
<p>在实现以上代码后，这是我们导航栏的最终外观。这也标志着我们 Flexbox 部分的结束。接下来，我们将使用 CSS Grid 构建我们网页的最后一部分。</p>
<h1 id="cssgrid">如何使用 CSS Grid</h1>
<p>CSS Grid 是一个改变生活的工具，用于创建网页布局。它可以帮助您创建简单和复杂的布局。主要区别在于 Flexbox 用于一维元素的排列，而 CSS Grid 则能够进行二维排列。</p>
<p>在 Flexbox 中学到的轴的概念在 CSS Grid 中仍然适用。您可以使用 CSS Grid 同时在主轴和交叉轴上排列元素。</p>
<p>总的来说，Flexbox 可以使您在水平方向（行）或垂直方向（列）上排列元素。而 CSS Grid 则可以同时在垂直和水平方向上对元素进行对齐。</p>
<p>CSS Grid 布局仅在父元素或容器上声明。实际上，它的所有子元素都成为网格项。一旦确定了目标容器，您可以为其添加 display: grid; 属性来声明它为网格容器。通过 <code>grid-template-rows</code> 和 <code>grid-template-columns</code> 属性，可以分别确定网格行和列的大小。</p>
<h2 id="">如何构建主页</h2>
<p>就像我们在导航栏中所做的那样，让我们从在 HTML 文件中的 <code>&lt;main&gt;</code> 部分定义我们的内容开始。</p>
<p>根据我们的目标图像，我们有两个主要的部分：左侧部分将包含文本和标志，而右侧部分将有一个主要图片。这是我们项目的网页视图。</p>
<p>让我们先定义我们的内容。具有 class 为 "text-side" 的部分包含：标题、段落文本、按钮和标志。具有 class 为 "img-side" 的部分只包含一张图片。</p>
<pre><code class="language-HTML">&lt;main&gt;
      &lt;section id="text-side"&gt;
        &lt;h1&gt;Make &lt;br /&gt;remote work&lt;/h1&gt;
        &lt;p&gt;
          Get your team in sync, no matter your location. Streamline processes,
          create team rituals, and watch productivity soar.
        &lt;/p&gt;
        &lt;button&gt;Learn more&lt;/button&gt;
        &lt;div class="clients-logos"&gt;
          &lt;img src="./assets/images/client-databiz.svg" /&gt;
          &lt;img src="./assets/images/client-audiophile.svg" /&gt;
          &lt;img src="./assets/images/client-meet.svg" /&gt;
          &lt;img src="./assets/images/client-maker.svg" /&gt;
        &lt;/div&gt;
      &lt;/section&gt;
      &lt;section class="img-side"&gt;
        &lt;img src="./assets/images/image-hero-desktop.png" /&gt;
      &lt;/section&gt;
    &lt;/main&gt;
</code></pre>
<p>主页部分的HTML代码</p>
<p>在主 main 部分中，我们创建了两个所需的部分，并为它们提供了描述性的 id：text-side 和 img-side。</p>
<p>在 text-side 内部，我们添加了一个标题、段落文本、按钮和一个用于显示客户标志的 div。而对于 img-side，我们只需要显示图像。</p>
<pre><code class="language-CSS">/* Client Logos */
.clients-logos img {
  width: 5rem;
  margin-right: 1rem;
}

.clients-logos {
  margin-top: 4rem;
}

.clients-logos img:nth-child(2) {
  width: 3rem;
}

/* Main */
main h1 {
  font-size: 3rem;
}

main p {
  font-size: 0.7rem;
  width: 18rem;
  color: hsl(0, 0%, 41%);
  line-height: 0.9rem;
}

main button {
  background-color: hsl(0, 0%, 8%);
  color: #fff;
  border: none;
  font-size: 0.7rem;
  padding: 0.6rem 1rem;
  border-radius: 0.4rem;
  margin-top: 1rem;
}

#text-side {
  margin-top: 3rem;
}
/* Hero Image */
.img-side img {
  width: 20rem;
}
</code></pre>
<p>主页部分的CSS代码</p>
<p>在我们的 CSS 文件中，我们需要为客户Logo的 div 和其子元素设置样式。我们还为标题和段落设置了字体大小。接下来，我们将为按钮设置样式，并为图像分配一个宽度。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/pregrid1-2.png" alt="pregrid1-2" width="600" height="400" loading="lazy"></p>
<p>上面的图片展示了在定义内容并仅对标题、按钮和标志进行样式设置后，我们的网页将呈现的样子。也就是说，我们还没有将容器声明为网格。由于我们这里几乎所有的元素都是块级元素，所以我们看到它们垂直堆叠在一起。</p>
<h2 id="">网格模板行和列</h2>
<p><code>grid-template-columns</code> 属性用于指定网格中列的数量和宽度，通过定义网格容器的列来指定轨道（track）的大小和线名（line names）。</p>
<p><code>grid-template-rows</code> 属性与之相反。它用于指定网格中行的数量和高度，通过定义网格容器的行来指定轨道（track）的大小和线名（line names）。</p>
<p>正如您在下面的图片中所看到的，<code>grid-template-rows</code> 将元素从设备屏幕的顶部排列到底部。而 <code>grid-template-columns</code> 则将元素从设备屏幕的左侧排列到右侧。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/CSS-Grid.png" alt="CSS-Grid" width="600" height="400" loading="lazy"></p>
<p>对于我们的项目，我们将使用 <code>grid-template-columns</code>，因为我们希望将两个部分并排排列，让每个部分占据整体项目宽度的相等部分。我们通过将其作为属性分配给与之前指定为网格显示的容器相同的元素来实现这一点。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/displaygrid.png" alt="displaygrid" width="600" height="400" loading="lazy"></p>
<p>现在，我们已经通过使用 grid-template-columns 将 <code>&lt;main&gt;</code> 标签内的两个部分等分布局好了，接下来还有两件事情要做。</p>
<p>我们需要通过将两个元素定位在页面中央，使它们水平对齐，图像左侧有多余的空白空间，左右两侧均匀分布。我们还需要通过将它们定位在页面中央，使它们垂直对齐，底部有多余的空白空间，上下均匀分布。</p>
<h2 id="css">在CSS网格中对齐和调整</h2>
<p>好消息是，为了在 CSS Grid 布局中实现我们期望的对齐方式，我们不需要学习任何新概念。因为幸运的是，正如我们之前学到的那样，<code>align-items</code> 和 <code>justify-content</code> 并不仅适用于 Flexbox。你也可以使用它们来在水平和垂直方向上定位元素。</p>
<pre><code class="language-CSS">main {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  height: 70vh;
  align-items: center;
  justify-content: center;
  margin-left: 8rem;
}
</code></pre>
<p>对齐和居中的CSS代码</p>
<p>正如你在上面的代码中所看到的，我们只需要在父标签（网格容器）上将 align-items 和 justify-content 属性的值都设置为 center。</p>
<p>为了确保我们能看到完美居中的效果，我们还需要为该部分指定一个高度。下面的图片是我们项目的最终输出结果。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/homepage-4.png" alt="homepage-4" width="600" height="400" loading="lazy"></p>
<h2 id="">如何使其具有响应性</h2>
<p>到目前为止，我们所构建的都是针对网页的。但考虑到希望在移动设备上访问登陆页面的用户，我们必须确保我们的项目在较小的屏幕上可访问。在我们的情况下，我们关注的屏幕尺寸是大于300像素但小于480像素的范围。</p>
<p>正如您在下面的代码中所看到的，我们正在隐藏我们的导航项，并显示一个具有 mobile-nav 类的表情符号。除此之外，我们隐藏了桌面版的页眉图像，并显示了移动版的页眉图像。</p>
<pre><code class="language-CSS">/* Responsive */
@media (min-width: 300px) and (max-width: 480px) {
  * {
    font-size: 1rem;
  }

  body {
    height: 100vh;
    width: 100vw;
    overflow-y: hidden;
    overflow-x: hidden;
  }

  nav {
    margin: 0 1.5rem 0 1.5rem;
  }

  nav ul {
    display: none;
  }
  
  .mobile-nav {
    display: block;
    margin-right: 2rem;
  }

  main {
    display: grid;
    grid-template-columns: 100%;
    margin: 0 auto;
  }

  /* Clients logos */
  .clients-logos {
    margin-top: 2rem;
  }
  
  .desktop-logos {
    display: none;
  }
  
  .mobile-logos {
    display: block;
  }

  /* Images */
  .desktop-img {
    display: none;
  }
  .mobile-img {
    display: block;
    margin-top: 3rem;
  }

  .cta-btns,
  .menu-items {
    display: none;
  }

  main h1 {
    font-size: 2.5rem;
  }

  /* Client Logos */
  .clients-logos img {
    width: 4.5rem;
    margin-right: 0.8rem;
  }

  .attribution {
    width: 13rem;
    margin: 8rem auto 0 auto;
    text-align: center;
  }
}
</code></pre>
<p>项目响应式的代码</p>
<h2 id="">完整的项目代码</h2>
<p>这就是我们在这篇文章中一起构建的项目：</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/homepage-3.png" alt="homepage-3" width="600" height="400" loading="lazy"></p>
<p>这是完整的HTML代码：</p>
<pre><code class="language-HTML">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8" /&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt;
    &lt;!-- displays site properly based on user's device --&gt;
    &lt;link rel="preconnect" href="https://fonts.googleapis.com" /&gt;
    &lt;link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /&gt;
    &lt;link
      href="https://fonts.googleapis.com/css2?family=Epilogue:wght@500;700&amp;family=Poppins:wght@400;500;700&amp;display=swap"
      rel="stylesheet"
    /&gt;
    &lt;link rel="stylesheet" href="style.css" /&gt;
    &lt;link
      rel="icon"
      type="image/png"
      sizes="32x32"
      href="./images/favicon-32x32.png"
    /&gt;

    &lt;title&gt;Web Layout | Landing Page&lt;/title&gt;

    &lt;!-- Feel free to remove these styles or customise in your own stylesheet 👍 --&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;nav&gt;
      &lt;div class="logos-section"&gt;
        &lt;h2 class="logo"&gt;snap&lt;/h2&gt;
        &lt;ul class="menu-items"&gt;
          &lt;li&gt;
            Features&lt;svg
              width="10"
              height="6"
              xmlns="http://www.w3.org/2000/svg"
            &gt;
              &lt;path
                stroke="#686868"
                stroke-width="1.5"
                fill="none"
                d="m1 1 4 4 4-4"
              /&gt;
            &lt;/svg&gt;
          &lt;/li&gt;
          &lt;li&gt;
            Company&lt;svg
              width="10"
              height="6"
              xmlns="http://www.w3.org/2000/svg"
            &gt;
              &lt;path
                stroke="#686868"
                stroke-width="1.5"
                fill="none"
                d="m1 1 4 4 4-4"
              /&gt;
            &lt;/svg&gt;
          &lt;/li&gt;
          &lt;li&gt;Careers&lt;/li&gt;
          &lt;li&gt;About&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
      &lt;ul class="cta-btns"&gt;
        &lt;li&gt;Login&lt;/li&gt;
        &lt;li&gt;Register&lt;/li&gt;
      &lt;/ul&gt;
      &lt;p class="mobile-nav"&gt;🌚&lt;/p&gt;
    &lt;/nav&gt;
    &lt;main&gt;
      &lt;section id="text-side"&gt;
        &lt;h1&gt;Make &lt;br /&gt;remote work&lt;/h1&gt;
        &lt;p&gt;
          Get your team in sync, no matter your location. Streamline processes,
          create team rituals, and watch productivity soar.
        &lt;/p&gt;
        &lt;button&gt;Learn more&lt;/button&gt;
        &lt;div class="clients-logos"&gt;
          &lt;img src="https://i.postimg.cc/gJ9Y84m6/client-databiz.png" /&gt;
          &lt;img src="https://i.postimg.cc/15DDqYSD/client-audiophile.png" /&gt;
          &lt;img src="https://i.postimg.cc/5ybQqfbv/client-meet.png" /&gt;
          &lt;img src="https://i.postimg.cc/g2NsxByN/client-maker.png" /&gt;
        &lt;/div&gt;
      &lt;/section&gt;
      &lt;section id="img-side"&gt;
        &lt;img
          class="desktop-img"
          src="https://i.postimg.cc/0Nt97Bhf/image-hero-desktop.png"
        /&gt;
        &lt;img
          class="mobile-img"
          src="https://i.postimg.cc/ZnYfhwwW/image-hero-mobile.png"
        /&gt;
      &lt;/section&gt;
    &lt;/main&gt;
    &lt;div class="attribution"&gt;
      Challenge by
      &lt;a href="https://www.frontendmentor.io?ref=challenge" target="_blank"
        &gt;Frontend Mentor&lt;/a
      &gt;. Coded by &lt;a href="https://codehemaa.com"&gt;Ophy Boamah&lt;/a&gt;.
    &lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>项目的HTML代码</p>
<p>这是完整的CSS代码：</p>
<pre><code class="language-CSS">* {
  font-family: "Epilogue", sans-serif;
  font-size: 1.3rem;
}

.logo {
  font-size: 1.3rem;
}

li {
  list-style: none;
}

nav,
.cta-btns,
.menu-items {
  display: flex;
  align-items: center;
}

nav {
  margin: 0 1.5rem 1.5rem 1.5rem;
  justify-content: space-between;
}

.mobile-nav {
    display: none;
}

.logos-section {
  display: flex;
}

.menu-items li,
.cta-btns li {
  font-size: 0.7rem;
  margin-right: 1rem;
  color: hsl(0, 0%, 41%);
}

.cta-btns li:nth-last-child(1) {
  border: 1px solid gray;
  padding: 0.2rem 0.7rem;
  border-radius: 0.3rem;
}

/* Client Logos */
  
.clients-logos img {
  width: 8rem;
  margin-right: -3rem;
}

.clients-logos {
  margin-top: 1rem;
  margin-left: -2rem;
  display: flex;
  width: 10rem;
}

.clients-logos img:nth-child(2) {
  width: 7rem;
}

/* Main */
main {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  height: 70vh;
  align-items: center;
  justify-content: center;
  margin-left: 8rem;
}
/* Images */
.desktop-img {
  display: block;
}
.mobile-img {
  display: none;
}

main h1 {
  font-size: 3rem;
}

main p {
  font-size: 0.7rem;
  width: 18rem;
  color: hsl(0, 0%, 41%);
  line-height: 0.9rem;
}

main button {
  background-color: hsl(0, 0%, 8%);
  color: #fff;
  border: none;
  font-size: 0.7rem;
  padding: 0.6rem 1rem;
  border-radius: 0.4rem;
  margin-top: 1rem;
}

#text-side {
  margin-top: 3rem;
}
/* Hero Image */
#img-side img {
  width: 20rem;
}

.attribution {
  font-size: 0.7rem;
  text-align: center;
  margin-top: 5.5rem;
}

.attribution a {
  color: hsl(228, 45%, 44%);
  font-size: 0.7rem;
}

/* Responsive */
@media (min-width: 300px) and (max-width: 480px) {
  * {
    font-size: 1rem;
  }

  body {
    height: 100vh;
    width: 100vw;
    overflow-y: hidden;
    overflow-x: hidden;
  }

  nav {
    margin: 0 1.5rem 0 1.5rem;
  }

  nav ul {
    display: none;
  }
  
  .mobile-nav {
    display: block;
    margin-right: 2rem;
  }

  main {
    display: grid;
    grid-template-columns: 100%;
    margin: -3rem auto 0 auto;
  }

  /* Clients logos */
  .clients-logos {
    margin-top: 2rem;
  }
  
  .clients-logos img {
  width: 30rem;
}

.clients-logos {
  margin-top: 1rem;
  display: flex;
}

.clients-logos img:nth-child(2) {
  width: 7rem;
}

  /* Images */
  .desktop-img {
    display: none;
  }
  .mobile-img {
    display: block;
    margin-top: 3rem;
  }

  .cta-btns,
  .menu-items {
    display: none;
  }

  main h1 {
    font-size: 2.5rem;
  }

  /* Client Logos */
  .clients-logos img {
    width: 4.5rem;
    margin-right: 0.8rem;
  }

  .attribution {
    width: 13rem;
    margin: 10rem auto 0 auto;
    text-align: center;
  }
}
</code></pre>
<p>项目的CSS代码：</p>
<h2 id="">总结</h2>
<p>作为网页开发者，在编写代码之前，布局应该是你首先考虑的事情。幸运的是，CSS Grid 和 Flexbox 已经彻底改变了我们构建网站和 Web 应用布局的方式。</p>
<p>这使得这些概念成为必须掌握的内容，这样你就可以在网页上指定元素的排列方式。我们已经讨论了基础知识，这样你就可以轻松地增加知识，并创建出漂亮的网页和应用程序。</p>
<p>谢谢阅读👋🏾 希望你觉得这篇文章对你有帮助。</p>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 从零开始实现一个玩具版浏览器渲染引擎 ]]>
                </title>
                <description>
                    <![CDATA[ 浏览器渲染原理作为前端必须要了解的知识点之一，在面试中经常会被问到。在一些前端书籍或者培训课程里也会经常被提及，比如 MDN 文档中就有渲染原理 [https://developer.mozilla.org/zh-CN/docs/Web/Performance/How_browsers_work#%E6%B8%B2%E6%9F%93] 的相关描述。 作为一名工作多年的前端，我对于渲染原理自然也是了解的，但是对于它的理解只停留在理论知识层面。所以我决定自己动手实现一个玩具版的渲染引擎。 渲染引擎是浏览器的一部分，它负责将网页内容（HTML、CSS、JavaScript 等）转化为用户可阅读、观看、听到的形式。但是要独自实现一个完整的渲染引擎工作量实在太大了，而且也很困难。于是我决定退一步，打算实现一个玩具版的渲染引擎。刚好 Github 上有一个开源的用 Rust 写的玩具版渲染引擎 robinson [https://github.com/woai3c/tiny-rendering-engine]，于是决定模仿其源码自己用 JavaScript 实现一遍，并且也在 Github 上 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/browser-rendering-engine/</link>
                <guid isPermaLink="false">64fed78058a38a1950d360df</guid>
                
                    <category>
                        <![CDATA[ 浏览器 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ woai3c ]]>
                </dc:creator>
                <pubDate>Tue, 12 Sep 2023 03:35:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2023/09/1694616133719.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>浏览器渲染原理作为前端必须要了解的知识点之一，在面试中经常会被问到。在一些前端书籍或者培训课程里也会经常被提及，比如 MDN 文档中就有<a href="https://developer.mozilla.org/zh-CN/docs/Web/Performance/How_browsers_work#%E6%B8%B2%E6%9F%93">渲染原理</a>的相关描述。</p><p>作为一名工作多年的前端，我对于渲染原理自然也是了解的，但是对于它的理解只停留在理论知识层面。所以我决定自己动手实现一个玩具版的渲染引擎。</p><p>渲染引擎是浏览器的一部分，它负责将网页内容（HTML、CSS、JavaScript 等）转化为用户可阅读、观看、听到的形式。但是要独自实现一个完整的渲染引擎工作量实在太大了，而且也很困难。于是我决定退一步，打算实现一个玩具版的渲染引擎。刚好 Github 上有一个开源的用 Rust 写的玩具版渲染引擎 <a href="https://github.com/woai3c/tiny-rendering-engine">robinson</a>，于是决定模仿其源码自己用 JavaScript 实现一遍，并且也在 Github 上开源了<a href="https://github.com/woai3c/tiny-rendering-engine">从零开始实现一个玩具版浏览器渲染引擎</a>。</p><p>这个玩具版的渲染引擎一共分为五个阶段：</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-266e8e94510504d11b930612229012ac_1440w.webp" class="kg-image" alt="v2-266e8e94510504d11b930612229012ac_1440w" width="600" height="400" loading="lazy"></figure><p>分别是：</p><ol><li>解析 HTML，生成 DOM 树</li><li>解析 CSS，生成 CSS 规则集合</li><li>生成 Style 树</li><li>生成布局树</li><li>绘制</li></ol><p>每个阶段的代码我在仓库上都用一个分支来表示。由于直接看整个渲染引擎的代码可能会比较困难，所以我建议大家从第一个分支开始进行学习，从易到难，这样学习效果更好。</p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-27a55d7173240190324c2f9d18b02a32_1440w.webp" class="kg-image" alt="v2-27a55d7173240190324c2f9d18b02a32_1440w" width="600" height="400" loading="lazy"></figure><p>现在我们先看一下如何编写一个 HTML 解析器。</p><h3 id="html-">HTML 解析器</h3><p>HTML 解析器的作用就是将一连串的 HTML 文本解析为 DOM 树。比如将这样的 HTML 文本：</p><pre><code class="language-html">&lt;div class="lightblue test" id=" div " data-index="1"&gt;test!&lt;/div&gt;</code></pre><p>解析为一个 DOM 树：</p><pre><code class="language-js">{
    "tagName": "div",
    "attributes": {
        "class": "lightblue test",
        "id": "div",
        "data-index": "1"
    },
    "children": [
        {
            "nodeValue": "test!",
            "nodeType": 3
        }
    ],
    "nodeType": 1
}
</code></pre><p>写解析器需要懂一些编译原理的知识，比如词法分析、语法分析什么的。但是我们的玩具版解析器非常简单，即使不懂也没有关系，大家看源码就能明白了。</p><p>再回到上面的那段 HTML 文本，它的整个解析过程可以用下面的图来表示，每一段 HTML 文本都有对应的方法去解析。</p><figure class="kg-card kg-image-card"><img src="https://pic4.zhimg.com/80/v2-19271cbd4bdf074f13f0351d39415b4f_1440w.webp" class="kg-image" alt="v2-19271cbd4bdf074f13f0351d39415b4f_1440w" width="600" height="400" loading="lazy"></figure><p>为了让解析器实现起来简单一点，我们需要对 HTML 的功能进行约束：</p><ol><li>标签必须要成对出现：<code>&lt;div&gt;...&lt;/div&gt;</code></li><li>HTML 属性值必须要有引号包起来 <code>&lt;div class="test"&gt;...&lt;/div&gt;</code></li><li>不支持注释</li><li>尽量不做错误处理</li><li>只支持两种类型节点 <code>Element</code> 和 <code>Text</code></li></ol><p>对解析器的功能进行约束后，代码实现就变得简单多了，现在让我们继续吧。</p><h3 id="-">节点类型</h3><p>首先，为这两种节点 <code>Element</code> 和 <code>Text</code> 定一个适当的数据结构：</p><pre><code class="language-ts">export enum NodeType {
    Element = 1,
    Text = 3,
}

export interface Element {
    tagName: string
    attributes: Record&lt;string, string&gt;
    children: Node[]
    nodeType: NodeType.Element
}

interface Text {
    nodeValue: string
    nodeType: NodeType.Text
}

export type Node = Element | Text
</code></pre><p>然后为这两种节点各写一个生成函数：</p><pre><code class="language-ts">export function element(tagName: string) {
    return {
        tagName,
        attributes: {},
        children: [],
        nodeType: NodeType.Element,
    } as Element
}

export function text(data: string) {
    return {
        nodeValue: data,
        nodeType: NodeType.Text,
    } as Text
}
</code></pre><p>这两个函数在解析到元素节点或者文本节点时调用，调用后会返回对应的 DOM 节点。</p><h3 id="html--1">HTML 解析器的执行过程</h3><p>下面这张图就是整个 HTML 解析器的执行过程：</p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-5fc6cad8bfec2129f8f1c82cb71175a2_1440w.webp" class="kg-image" alt="v2-5fc6cad8bfec2129f8f1c82cb71175a2_1440w" width="600" height="400" loading="lazy"></figure><p>HTML 解析器的入口方法为 <code>parse()</code>，从这开始执行直到遍历完所有 HTML 文本为止：</p><ol><li>判断当前字符是否为 <code>&lt;</code>，如果是，则当作元素节点来解析，调用 <code>parseElement()</code>，否则调用 <code>parseText()</code></li><li><code>parseText()</code> 比较简单，一直往前遍历字符串，直至遇到 <code>&lt;</code> 字符为止。然后将之前遍历过的所有字符当作 <code>Text</code> 节点的值。</li><li><code>parseElement()</code> 则相对复杂一点，它首先要解析出当前的元素标签名称，这段文本用 <code>parseTag()</code> 来解析。</li><li>然后再进入 <code>parseAttrs()</code> 方法，判断是否有属性节点，如果该节点有 <code>class</code> 或者其他 HTML 属性，则会调用 <code>parseAttr()</code> 把 HTML 属性或者 <code>class</code> 解析出来。</li><li>至此，整个元素节点的前半段已经解析完了。接下来需要解析它的子节点。这时就会进入无限递归循环回到第一步，继续解析元素节点或文本节点。</li><li>当所有子节点解析完后，需要调用 <code>parseTag()</code>，看看结束标签名和元素节点的开始标签名是否相同，如果相同，则 <code>parseElement()</code> 或者 <code>parse()</code> 结束，否则报错。</li></ol><h3 id="html--2">HTML 解析器各个方法详解</h3><h3 id="-parse-">入口方法 parse()</h3><p>HTML 的入口方法是 <code>parse(rawText)</code></p><pre><code class="language-ts">parse(rawText: string) {
    this.rawText = rawText.trim()
    this.len = this.rawText.length
    this.index = 0
    this.stack = []

    const root = element('root')
    while (this.index &lt; this.len) {
        this.removeSpaces()
        if (this.rawText[this.index].startsWith('&lt;')) {
            this.index++
            this.parseElement(root)
        } else {
            this.parseText(root)
        }
    }
}
</code></pre><p>入口方法需要遍历所有文本，在一开始它需要判断当前字符是否是 <code>&lt;</code>，如果是，则将它当作元素节点来解析，调用 <code>parseElement()</code>，否则将当前字符作为文本来解析，调用 <code>parseText()</code>。</p><h3 id="-parseelement-">解析元素节点 <code>parseElement()</code></h3><pre><code class="language-ts">private parseElement(parent: Element) {
 // 解析标签
    const tag = this.parseTag()
    // 生成元素节点
    const ele = element(tag)

    this.stack.push(tag)

    parent.children.push(ele)
    // 解析属性
    this.parseAttrs(ele)

    while (this.index &lt; this.len) {
        this.removeSpaces()
        if (this.rawText[this.index].startsWith('&lt;')) {
            this.index++
            this.removeSpaces()
            // 判断是否是结束标签
            if (this.rawText[this.index].startsWith('/')) {
                this.index++
                const startTag = this.stack[this.stack.length - 1]
                // 结束标签
                const endTag = this.parseTag()
                if (startTag !== endTag) {
                    throw Error(`The end tagName ${endTag} does not match start tagName ${startTag}`)
                }

                this.stack.pop()
                while (this.index &lt; this.len &amp;&amp; this.rawText[this.index] !== '&gt;') {
                    this.index++
                }

                break
            } else {
                this.parseElement(ele)
            }
        } else {
            this.parseText(ele)
        }
    }

    this.index++
}
</code></pre><p><code>parseElement()</code> 会依次调用 <code>parseTag()</code> <code>parseAttrs()</code> 解析标签和属性，然后再递归解析子节点，终止条件是遍历完所有的 HTML 文本。</p><h3 id="-parsetext-">解析文本节点 <code>parseText()</code></h3><pre><code class="language-ts">private parseText(parent: Element) {
    let str = ''
    while (
        this.index &lt; this.len
        &amp;&amp; !(this.rawText[this.index] === '&lt;' &amp;&amp; /\w|\//.test(this.rawText[this.index + 1]))
    ) {
        str += this.rawText[this.index]
        this.index++
    }

    this.sliceText()
    parent.children.push(text(removeExtraSpaces(str)))
}
</code></pre><p>解析文本相对简单一点，它会一直往前遍历，直至遇到 <code>&lt;</code> 为止。比如这段文本 <code>&lt;div&gt;test!&lt;/div&gt;</code>，经过 <code>parseText()</code> 解析后拿到的文本是 <code>test!</code>。</p><h3 id="-parsetag-">解析标签 <code>parseTag()</code></h3><p>在进入 <code>parseElement()</code> 后，首先调用就是 <code>parseTag()</code>，它的作用是解析标签名：</p><pre><code class="language-ts">private parseTag() {
    let tag = ''

    this.removeSpaces()

    // get tag name
    while (this.index &lt; this.len &amp;&amp; this.rawText[this.index] !== ' ' &amp;&amp; this.rawText[this.index] !== '&gt;') {
        tag += this.rawText[this.index]
        this.index++
    }

    this.sliceText()
    return tag
}
</code></pre><p>比如这段文本 <code>&lt;div&gt;test!&lt;/div&gt;</code>，经过 <code>parseTag()</code> 解析后拿到的标签名是 <code>div</code>。</p><h3 id="-parseattrs-">解析属性节点 <code>parseAttrs()</code></h3><p>解析完标签名后，接着再解析属性节点：</p><pre><code class="language-ts">// 解析元素节点的所有属性
private parseAttrs(ele: Element) {
 // 一直遍历文本，直至遇到 '&gt;' 字符为止，代表 &lt;div ....&gt; 这一段文本已经解析完了
    while (this.index &lt; this.len &amp;&amp; this.rawText[this.index] !== '&gt;') {
        this.removeSpaces()
        this.parseAttr(ele)
        this.removeSpaces()
    }

    this.index++
}

// 解析单个属性，例如 class="foo bar"
private parseAttr(ele: Element) {
    let attr = ''
    let value = ''
    while (this.index &lt; this.len &amp;&amp; this.rawText[this.index] !== '=' &amp;&amp; this.rawText[this.index] !== '&gt;') {
        attr += this.rawText[this.index++]
    }

    this.sliceText()
    attr = attr.trim()
    if (!attr.trim()) return

    this.index++
    let startSymbol = ''
    if (this.rawText[this.index] === "'" || this.rawText[this.index] === '"') {
        startSymbol = this.rawText[this.index++]
    }

    while (this.index &lt; this.len &amp;&amp; this.rawText[this.index] !== startSymbol) {
        value += this.rawText[this.index++]
    }

    this.index++
    ele.attributes[attr] = value.trim()
    this.sliceText()
}
</code></pre><p><code>parseAttr()</code> 可以将这样的文本 <code>class="test"</code> 解析为一个对象 <code>{ class: "test" }</code>。</p><h3 id="--1">其他辅助方法</h3><p>有时不同的节点、属性之间有很多多余的空格，所以需要写一个方法将多余的空格清除掉。</p><pre><code class="language-ts">protected removeSpaces() {
    while (this.index &lt; this.len &amp;&amp; (this.rawText[this.index] === ' ' || this.rawText[this.index] === '\n')) {
        this.index++
    }

    this.sliceText()
}
</code></pre><p>同时为了方便调试，开发者经常需要打断点看当前正在遍历的字符是什么。如果以前遍历过的字符串还在，那么是比较难调试的，因为开发者需要根据 index 的值自己去找当前遍历的字符是什么。所以所有解析完的 HTML 文本，都需要截取掉，确保当前的 HTML 文本都是没有被遍历：</p><pre><code class="language-ts">protected sliceText() {
    this.rawText = this.rawText.slice(this.index)
    this.len = this.rawText.length
    this.index = 0
}
</code></pre><p><code>sliceText()</code> 方法的作用就是截取已经遍历过的 HTML 文本。用下图来做例子，假设当前要解析 <code>div</code> 这个标签名：</p><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-d18d74c75c7c028b686132e9c2377b9d_1440w.webp" class="kg-image" alt="v2-d18d74c75c7c028b686132e9c2377b9d_1440w" width="600" height="400" loading="lazy"></figure><p>那么解析后需要对 HTML 文本进行截取，就像下图这样：</p><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-8a073dda6507fcb4e834339399065ba5_1440w.webp" class="kg-image" alt="v2-8a073dda6507fcb4e834339399065ba5_1440w" width="600" height="400" loading="lazy"></figure><h3 id="--2">小结</h3><p>至此，整个 HTML 解析器的逻辑已经讲完了，所有代码加起来 200 行左右，如果不算 TS 各种类型声明，代码只有 100 多行。</p><h3 id="css-">CSS 解析器</h3><p>CSS 样式表是一系列的 CSS 规则集合，而 CSS 解析器的作用就是将 CSS 文本解析为 CSS 规则集合。</p><pre><code class="language-css">div, p {
    font-size: 88px;
    color: #000;
}</code></pre><p>例如上面的 CSS 文本，经过解析器解析后，会生成下面的 CSS 规则集合：</p><pre><code class="language-js">[
    {
        "selectors": [
            {
                "id": "",
                "class": "",
                "tagName": "div"
            },
            {
                "id": "",
                "class": "",
                "tagName": "p"
            }
        ],
        "declarations": [
            {
                "name": "font-size",
                "value": "88px"
            },
            {
                "name": "color",
                "value": "#000"
            }
        ]
    }
]
</code></pre><p>每个规则都有一个 <code>selector</code> 和 <code>declarations</code> 属性，其中 <code>selectors</code> 表示 CSS 选择器，<code>declarations</code> 表示 CSS 的属性描述集合。</p><pre><code class="language-ts">export interface Rule {
    selectors: Selector[]
    declarations: Declaration[]
}

export interface Selector {
    tagName: string
    id: string
    class: string
}

export interface Declaration {
    name: string
    value: string | number
}
</code></pre><figure class="kg-card kg-image-card"><img src="https://pic4.zhimg.com/80/v2-4ae9e0e860a5248e0e4e3a82f2c983eb_1440w.webp" class="kg-image" alt="v2-4ae9e0e860a5248e0e4e3a82f2c983eb_1440w" width="600" height="400" loading="lazy"></figure><p>每一条 CSS 规则都可以包含多个选择器和多个 CSS 属性。</p><h3 id="-css-parserule-">解析 CSS 规则 <code>parseRule()</code></h3><pre><code class="language-ts">private parseRule() {
    const rule: Rule = {
        selectors: [],
        declarations: [],
    }

    rule.selectors = this.parseSelectors()
    rule.declarations = this.parseDeclarations()

    return rule
}
</code></pre><p>在 <code>parseRule()</code> 里，它分别调用了 <code>parseSelectors()</code> 去解析 CSS 选择器，然后再对剩余的 CSS 文本执行 <code>parseDeclarations()</code> 去解析 CSS 属性。</p><h3 id="-parseselector-">解析选择器 <code>parseSelector()</code></h3><pre><code class="language-ts">private parseSelector() {
    const selector: Selector = {
        id: '',
        class: '',
        tagName: '',
    }

    switch (this.rawText[this.index]) {
        case '.':
            this.index++
            selector.class = this.parseIdentifier()
            break
        case '#':
            this.index++
            selector.id = this.parseIdentifier()
            break
        case '*':
            this.index++
            selector.tagName = '*'
            break
        default:
            selector.tagName = this.parseIdentifier()
    }

    return selector
}

private parseIdentifier() {
    let result = ''
    while (this.index &lt; this.len &amp;&amp; this.identifierRE.test(this.rawText[this.index])) {
        result += this.rawText[this.index++]
    }

    this.sliceText()
    return result
}
</code></pre><p>选择器我们只支持标签名称、前缀为 <code>#</code> 的 ID 、前缀为任意数量的类名 <code>.</code> 或上述的某种组合。如果标签名称为 <code>*</code>，则表示它是一个通用选择器，可以匹配任何标签。</p><p>标准的 CSS 解析器在遇到无法识别的部分时，会将它丢掉，然后继续解析其余部分。主要是为了兼容旧浏览器和防止发生错误导致程序中断。我们的 CSS 解析器为了实现简单，没有做这方面的做错误处理。</p><h3 id="-css-parsedeclaration-">解析 CSS 属性 <code>parseDeclaration()</code></h3><pre><code class="language-ts">private parseDeclaration() {
    const declaration: Declaration = { name: '', value: '' }
    this.removeSpaces()
    declaration.name = this.parseIdentifier()
    this.removeSpaces()

    while (this.index &lt; this.len &amp;&amp; this.rawText[this.index] !== ':') {
        this.index++
    }

    this.index++ // clear :
    this.removeSpaces()
    declaration.value = this.parseValue()
    this.removeSpaces()

    return declaration
}
</code></pre><p><code>parseDeclaration()</code> 会将 <code>color: red;</code> 解析为一个对象 <code>{ name: "color", value: "red" }</code>。</p><h3 id="--3">小结</h3><p>CSS 解析器相对来说简单多了，因为很多知识点在 HTML 解析器中已经讲到。整个 CSS 解析器的代码大概 100 多行，如果你阅读过 HTML 解析器的源码，相信看 CSS 解析器的源码会更轻松。</p><h3 id="--4">构建样式树</h3><p>本阶段的目标是写一个样式构建器，输入 DOM 树和 CSS 规则集合，生成一棵样式树 Style tree。</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-266e8e94510504d11b930612229012ac_1440w.webp" class="kg-image" alt="v2-266e8e94510504d11b930612229012ac_1440w" width="600" height="400" loading="lazy"></figure><p>样式树的每一个节点都包含了 CSS 属性值以及它对应的 DOM 节点引用：</p><pre><code class="language-ts">interface AnyObject {
    [key: string]: any
}

export interface StyleNode {
    node: Node // DOM 节点
    values: AnyObject // style 属性值
    children: StyleNode[] // style 子节点
}
</code></pre><p>先来看一个简单的示例：</p><pre><code class="language-html">&lt;div&gt;test&lt;/div&gt;
div {
    font-size: 88px;
    color: #000;
}</code></pre><p>上述的 HTML、CSS 文本在经过样式树构建器处理后生成的样式树如下：</p><pre><code class="language-js">{
    "node": { // DOM 节点
        "tagName": "div",
        "attributes": {},
        "children": [
            {
                "nodeValue": "test",
                "nodeType": 3
            }
        ],
        "nodeType": 1
    },
    "values": { // CSS 属性值
        "font-size": "88px",
        "color": "#000"
    },
    "children": [ // style tree 子节点
        {
            "node": {
                "nodeValue": "test",
                "nodeType": 3
            },
            "values": { // text 节点继承了父节点样式
                "font-size": "88px",
                "color": "#000"
            },
            "children": []
        }
    ]
}
</code></pre><h3 id="-dom-">遍历 DOM 树</h3><p>现在我们需要遍历 DOM 树。对于 DOM 树中的每个节点，我们都要在样式树中查找是否有匹配的 CSS 规则。</p><pre><code class="language-ts">export function getStyleTree(eles: Node | Node[], cssRules: Rule[], parent?: StyleNode) {
    if (Array.isArray(eles)) {
        return eles.map((ele) =&gt; getStyleNode(ele, cssRules, parent))
    }

    return getStyleNode(eles, cssRules, parent)
}
</code></pre><h3 id="--5">匹配选择器</h3><p>匹配选择器实现起来非常容易，因为我们的CSS 解析器仅支持简单的选择器。 只需要查看元素本身即可判断选择器是否与元素匹配。</p><pre><code class="language-ts">/**
 * css 选择器是否匹配元素
 */
function isMatch(ele: Element, selectors: Selector[]) {
    return selectors.some((selector) =&gt; {
        // 通配符
        if (selector.tagName === '*') return true
        if (selector.tagName === ele.tagName) return true
        if (ele.attributes.id === selector.id) return true

        if (ele.attributes.class) {
            const classes = ele.attributes.class.split(' ').filter(Boolean)
            const classes2 = selector.class.split(' ').filter(Boolean)
            for (const name of classes) {
                if (classes2.includes(name)) return true
            }
        }

        return false
    })
}
</code></pre><p>当查找到匹配的 DOM 节点后，再将 DOM 节点和它匹配的 CSS 属性组合在一起，生成样式树节点 styleNode：</p><pre><code class="language-ts">function getStyleNode(ele: Node, cssRules: Rule[], parent?: StyleNode) {
    const styleNode: StyleNode = {
        node: ele,
        values: getStyleValues(ele, cssRules, parent),
        children: [],
    }

    if (ele.nodeType === NodeType.Element) {
        // 合并内联样式
        if (ele.attributes.style) {
            styleNode.values = { ...styleNode.values, ...getInlineStyle(ele.attributes.style) }
        }

        styleNode.children = ele.children.map((e) =&gt; getStyleNode(e, cssRules, styleNode)) as unknown as StyleNode[]
    }

    return styleNode
}

function getStyleValues(ele: Node, cssRules: Rule[], parent?: StyleNode) {
    const inheritableAttrValue = getInheritableAttrValues(parent)

    // 文本节点继承父元素的可继承属性
    if (ele.nodeType === NodeType.Text) return inheritableAttrValue

    return cssRules.reduce((result: AnyObject, rule) =&gt; {
        if (isMatch(ele as Element, rule.selectors)) {
            result = { ...result, ...cssValueArrToObject(rule.declarations) }
        }

        return result
    }, inheritableAttrValue)
}
</code></pre><p>在 CSS 选择器中，不同的选择器优先级是不同的，比如 id 选择器就比类选择器的优先级要高。但是我们这里没有实现选择器优先级，为了实现简单，所有的选择器优先级是一样的。</p><h3 id="--6">继承属性</h3><p>文本节点无法匹配选择器，那它的样式从哪来？答案就是继承，它可以继承父节点的样式。</p><p>在 CSS 中存在很多继承属性，即使子元素没有声明这些属性，也可以从父节点里继承。比如字体颜色、字体家族等属性，都是可以被继承的。为了实现简单，这里只支持继承父节点的 <code>color</code>、<code>font-size</code> 属性。</p><pre><code class="language-ts">// 子元素可继承的属性，这里只写了两个，实际上还有很多
const inheritableAttrs = ['color', 'font-size']

/**
 * 获取父元素可继承的属性值
 */
function getInheritableAttrValues(parent?: StyleNode) {
    if (!parent) return {}
    const keys = Object.keys(parent.values)
    return keys.reduce((result: AnyObject, key) =&gt; {
        if (inheritableAttrs.includes(key)) {
            result[key] = parent.values[key]
        }

        return result
    }, {})
}
</code></pre><h3 id="--7">内联样式</h3><p>在 CSS 中，内联样式的优先级是除了 <code>!important</code> 之外最高的。</p><pre><code class="language-html">&lt;span style="color: red; background: yellow;"&gt;</code></pre><p>我们可以在调用 <code>getStyleValues()</code> 函数获得当前 DOM 节点的 CSS 属性值后，再去取当前节点的内联样式值。并对当前 DOM 节点的 CSS 样式值进行覆盖。</p><pre><code class="language-ts">styleNode.values = { ...styleNode.values, ...getInlineStyle(ele.attributes.style) }

function getInlineStyle(str: string) {
    str = str.trim()
    if (!str) return {}
    const arr = str.split(';')
    if (!arr.length) return {}

    return arr.reduce((result: AnyObject, item: string) =&gt; {
        const data = item.split(':')
        if (data.length === 2) {
            result[data[0].trim()] = data[1].trim()
        }

        return result
    }, {})
}
</code></pre><h3 id="--8">布局树</h3><p>第四阶段讲的是如何将样式树转化为布局树，也是整个渲染引擎相对比较复杂的部分。</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-266e8e94510504d11b930612229012ac_1440w.webp" class="kg-image" alt="v2-266e8e94510504d11b930612229012ac_1440w" width="600" height="400" loading="lazy"></figure><h3 id="css--1">CSS 盒子模型</h3><p>在 CSS 中，所有的 DOM 节点都可以当作一个盒子。这个盒子模型包含了内容、内边距、边框、外边距以及在页面中的位置信息。</p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-6ca1a4d0cb14b09aea28fefe3dc91dc2_1440w.webp" class="kg-image" alt="v2-6ca1a4d0cb14b09aea28fefe3dc91dc2_1440w" width="600" height="400" loading="lazy"></figure><p>我们可以用以下的数据结构来表示盒子模型：</p><pre><code class="language-ts">export default class Dimensions {
    content: Rect
    padding: EdgeSizes
    border: EdgeSizes
    margin: EdgeSizes
}

export default class Rect {
    x: number
    y: number
    width: number
    height: number
}

export interface EdgeSizes {
    top: number
    right: number
    bottom: number
    left: number
}
</code></pre><h3 id="--9">块布局和内联布局</h3><p>CSS 的 <code>display</code> 属性决定了盒子在页面中的布局方式。<code>display</code> 的类型有很多种，例如 <code>block</code>、<code>inline</code>、<code>flex</code> 等等，但这里只支持 <code>block</code> 和 <code>inline</code> 两种布局方式，并且所有盒子的默认布局方式为 <code>display: inline</code>。</p><p>我会用伪 HTML 代码来描述它们之间的区别：</p><pre><code class="language-html">&lt;container&gt;
  &lt;a&gt;&lt;/a&gt;
  &lt;b&gt;&lt;/b&gt;
  &lt;c&gt;&lt;/c&gt;
  &lt;d&gt;&lt;/d&gt;
&lt;/container&gt;</code></pre><p>块布局会将盒子从上至下的垂直排列。</p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-02572058706b774cb4eb6d2920127b6a_1440w.webp" class="kg-image" alt="v2-02572058706b774cb4eb6d2920127b6a_1440w" width="600" height="400" loading="lazy"></figure><p>内联布局则会将盒子从左至右的水平排列。</p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-dbd175cba44b114a7a8fe74efac00b7a_1440w.webp" class="kg-image" alt="v2-dbd175cba44b114a7a8fe74efac00b7a_1440w" width="600" height="400" loading="lazy"></figure><p>如果容器内同时存在块布局和内联布局，则会用一个匿名布局将内联布局包裹起来。</p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-98271cb522c63a126d86abfd9648ed8e_1440w.webp" class="kg-image" alt="v2-98271cb522c63a126d86abfd9648ed8e_1440w" width="600" height="400" loading="lazy"></figure><p>这样就能将内联布局的盒子和其他块布局的盒子区别开来。</p><p>通常情况下内容是垂直增长的。也就是说，在容器中添加子节点通常会使容器更高，而不是更宽。另一种说法是，默认情况下，子节点的宽度取决于其容器的宽度，而容器的高度取决于其子节点的高度。</p><h3 id="--10">布局树</h3><p>布局树是所有盒子节点的集合。</p><pre><code class="language-ts">export default class LayoutBox {
 dimensions: Dimensions
 boxType: BoxType
 children: LayoutBox[]
 styleNode: StyleNode
}
</code></pre><p>盒子节点的类型可以是 <code>block</code>、<code>inilne</code> 和 <code>anonymous</code>。</p><pre><code class="language-ts">export enum BoxType {
    BlockNode = 'BlockNode',
    InlineNode = 'InlineNode',
    AnonymousBlock = 'AnonymousBlock',
}
</code></pre><p>我们构建样式树时，需要根据每一个 DOM 节点的 <code>display</code> 属性来生成对应的盒子节点。</p><pre><code class="language-ts">export function getDisplayValue(styleNode: StyleNode) {
    return styleNode.values?.display ?? Display.Inline
}
</code></pre><p>如果 DOM 节点 <code>display</code> 属性的值为 <code>none</code>，则在构建布局树的过程中，无需将这个 DOM 节点添加到布局树上，直接忽略它就可以了。</p><p>如果一个块节点包含一个内联子节点，则需要创建一个匿名块（实际上就是块节点）来包含它。如果一行中有多个子节点，则将它们全部放在同一个匿名容器中。</p><pre><code class="language-ts">function buildLayoutTree(styleNode: StyleNode) {
    if (getDisplayValue(styleNode) === Display.None) {
        throw new Error('Root node has display: none.')
    }

    const layoutBox = new LayoutBox(styleNode)

    let anonymousBlock: LayoutBox | undefined
    for (const child of styleNode.children) {
        const childDisplay = getDisplayValue(child)
        // 如果 DOM 节点 display 属性值为 none，直接跳过
        if (childDisplay === Display.None) continue

        if (childDisplay === Display.Block) {
            anonymousBlock = undefined
            layoutBox.children.push(buildLayoutTree(child))
        } else {
         // 创建一个匿名容器，用于容纳内联节点
            if (!anonymousBlock) {
                anonymousBlock = new LayoutBox()
                layoutBox.children.push(anonymousBlock)
            }

            anonymousBlock.children.push(buildLayoutTree(child))
        }
    }

    return layoutBox
}
</code></pre><h3 id="--11">遍历布局树</h3><p>现在开始构建布局树，入口函数是 <code>getLayoutTree()</code>：</p><pre><code class="language-ts">export function getLayoutTree(styleNode: StyleNode, parentBlock: Dimensions) {
    parentBlock.content.height = 0
    const root = buildLayoutTree(styleNode)
    root.layout(parentBlock)
    return root
}
</code></pre><p>它将遍历样式树，利用样式树节点提供的相关信息，生成一个 <code>LayoutBox</code> 对象，然后调用 <code>layout()</code> 方法。计算每个盒子节点的位置、尺寸信息。</p><p>在本节内容的开头有提到过，盒子的宽度取决于其父节点，而高度取决于子节点。这意味着，我们的代码在计算宽度时需要自上而下遍历树，这样它就可以在知道父节点的宽度后设置子节点的宽度。然后自下而上遍历以计算高度，这样父节点的高度就可以在计算子节点的相关信息后进行计算。</p><pre><code class="language-ts">layout(parentBlock: Dimensions) {
 // 子节点的宽度依赖于父节点的宽度，所以要先计算当前节点的宽度，再遍历子节点
    this.calculateBlockWidth(parentBlock)
    // 计算盒子节点的位置
    this.calculateBlockPosition(parentBlock)
    // 遍历子节点并计算对位置、尺寸信息
    this.layoutBlockChildren()
    // 父节点的高度依赖于其子节点的高度，所以计算子节点的高度后，再计算自己的高度
    this.calculateBlockHeight()
}
</code></pre><p>这个方法执行布局树的单次遍历，向下执行宽度计算，向上执行高度计算。一个真正的布局引擎可能会执行几次树遍历，有些是自上而下的，有些是自下而上的。</p><h3 id="--12">计算宽度</h3><p>现在，我们先来计算盒子节点的宽度，这部分比较复杂，需要详细的讲解。</p><p>首先，我们要拿到当前节点的 <code>width</code> <code>padding</code> <code>border</code> <code>margin</code> 等信息：</p><pre><code class="language-ts">calculateBlockWidth(parentBlock: Dimensions) {
 // 初始值
 const styleValues = this.styleNode?.values || {}

 // 初始值为 auto
 let width = styleValues.width ?? 'auto'
 let marginLeft = styleValues['margin-left'] || styleValues.margin || 0
 let marginRight = styleValues['margin-right'] || styleValues.margin || 0

 let borderLeft = styleValues['border-left'] || styleValues.border || 0
 let borderRight = styleValues['border-right'] || styleValues.border || 0

 let paddingLeft = styleValues['padding-left'] || styleValues.padding || 0
 let paddingRight = styleValues['padding-right'] || styleValues.padding || 0

 // 拿到父节点的宽度，如果某个属性为 'auto'，则将它设为 0
 let totalWidth = sum(width, marginLeft, marginRight, borderLeft, borderRight, paddingLeft, paddingRight)
 // ...
</code></pre><p>如果这些属性没有设置，就使用 0 作为默认值。拿到当前节点的总宽度后，还需要和父节点对比一下是否相等。如果宽度或边距设置为 <code>auto</code>，则可以对这两个属性进行适当展开或收缩以适应可用空间。所以现在需要对当前节点的宽度进行检查。</p><pre><code class="language-ts">const isWidthAuto = width === 'auto'
const isMarginLeftAuto = marginLeft === 'auto'
const isMarginRightAuto = marginRight === 'auto'

// 当前块的宽度如果超过了父元素宽度，则将它的可扩展外边距设为 0
if (!isWidthAuto &amp;&amp; totalWidth &gt; parentWidth) {
    if (isMarginLeftAuto) {
        marginLeft = 0
    }

    if (isMarginRightAuto) {
        marginRight = 0
    }
}

// 根据父子元素宽度的差值，去调整当前元素的宽度
const underflow = parentWidth - totalWidth

// 如果三者都有值，则将差值填充到 marginRight
if (!isWidthAuto &amp;&amp; !isMarginLeftAuto &amp;&amp; !isMarginRightAuto) {
    marginRight += underflow
} else if (!isWidthAuto &amp;&amp; !isMarginLeftAuto &amp;&amp; isMarginRightAuto) {
 // 如果右边距是 auto，则将 marginRight 设为差值
    marginRight = underflow
} else if (!isWidthAuto &amp;&amp; isMarginLeftAuto &amp;&amp; !isMarginRightAuto) {
 // 如果左边距是 auto，则将 marginLeft 设为差值
    marginLeft = underflow
} else if (isWidthAuto) {
    // 如果只有 width 是 auto，则将另外两个值设为 0
    if (isMarginLeftAuto) {
        marginLeft = 0
    }

    if (isMarginRightAuto) {
        marginRight = 0
    }

    if (underflow &gt;= 0) {
        // 展开宽度，填充剩余空间，原来的宽度是 auto，作为 0 来计算的
        width = underflow
    } else {
        // 宽度不能为负数，所以需要调整 marginRight 来代替
        width = 0
        // underflow 为负数，相加实际上就是缩小当前节点的宽度
        marginRight += underflow
    }
} else if (!isWidthAuto &amp;&amp; isMarginLeftAuto &amp;&amp; isMarginRightAuto) {
    // 如果只有 marginLeft 和 marginRight 是 auto，则将两者设为 underflow 的一半
    marginLeft = underflow / 2
    marginRight = underflow / 2
}
</code></pre><p>详细的计算过程请看上述代码，重要的地方都已经标上注释了。</p><p>通过对比当前节点和父节点的宽度，我们可以拿到一个差值：</p><pre><code class="language-ts">// 根据父子元素宽度的差值，去调整当前元素的宽度
const underflow = parentWidth - totalWidth
</code></pre><p>如果这个差值为正数，说明子节点宽度小于父节点；如果差值为负数，说明子节点大于父节。上面这段代码逻辑其实就是根据 <code>underflow</code> <code>width</code> <code>padding</code> <code>margin</code> 等值对子节点的宽度、边距进行调整，以适应父节点的宽度。</p><h3 id="--13">定位</h3><p>计算当前节点的位置相对来说简单一点。这个方法会根据当前节点的 <code>margin</code> <code>border</code> <code>padding</code> 样式以及父节点的位置信息对当前节点进行定位：</p><pre><code class="language-ts">calculateBlockPosition(parentBlock: Dimensions) {
 const styleValues = this.styleNode?.values || {}
 const { x, y, height } = parentBlock.content
 const dimensions = this.dimensions

 dimensions.margin.top = transformValueSafe(styleValues['margin-top'] || styleValues.margin || 0)
 dimensions.margin.bottom = transformValueSafe(styleValues['margin-bottom'] || styleValues.margin || 0)

 dimensions.border.top = transformValueSafe(styleValues['border-top'] || styleValues.border || 0)
 dimensions.border.bottom = transformValueSafe(styleValues['border-bottom'] || styleValues.border || 0)

 dimensions.padding.top = transformValueSafe(styleValues['padding-top'] || styleValues.padding || 0)
 dimensions.padding.bottom = transformValueSafe(styleValues['padding-bottom'] || styleValues.padding || 0)

 dimensions.content.x = x + dimensions.margin.left + dimensions.border.left + dimensions.padding.left
 dimensions.content.y = y + height + dimensions.margin.top + dimensions.border.top + dimensions.padding.top
}

function transformValueSafe(val: number | string) {
    if (val === 'auto') return 0
    return parseInt(String(val))
}
</code></pre><p>比如获取当前节点内容区域的 x 坐标，计算方式如下：</p><pre><code class="language-ts">dimensions.content.x = x + dimensions.margin.left + dimensions.border.left + dimensions.padding.left
</code></pre><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-23cf320afb0d12b4b25079d4d1a57805_1440w.webp" class="kg-image" alt="v2-23cf320afb0d12b4b25079d4d1a57805_1440w" width="600" height="400" loading="lazy"></figure><h3 id="--14">遍历子节点</h3><p>在计算高度之前，需要先遍历子节点，因为父节点的高度需要根据它下面子节点的高度进行适配。</p><pre><code class="language-ts">layoutBlockChildren() {
    const { dimensions } = this
    for (const child of this.children) {
        child.layout(dimensions)
        // 遍历子节点后，再计算父节点的高度
        dimensions.content.height += child.dimensions.marginBox().height
    }
}
</code></pre><p>每个节点的高度就是它上下两个外边距之间的差值，所以可以通过 <code>marginBox()</code> 获得高度：</p><pre><code class="language-ts">export default class Dimensions {
    content: Rect
    padding: EdgeSizes
    border: EdgeSizes
    margin: EdgeSizes

    constructor() {
        const initValue = {
            top: 0,
            right: 0,
            bottom: 0,
            left: 0,
        }

        this.content = new Rect()

        this.padding = { ...initValue }
        this.border = { ...initValue }
        this.margin = { ...initValue }
    }

    paddingBox() {
        return this.content.expandedBy(this.padding)
    }

    borderBox() {
        return this.paddingBox().expandedBy(this.border)
    }

    marginBox() {
        return this.borderBox().expandedBy(this.margin)
    }
}
export default class Rect {
    x: number
    y: number
    width: number
    height: number

    constructor() {
        this.x = 0
        this.y = 0
        this.width = 0
        this.height = 0
    }

    expandedBy(edge: EdgeSizes) {
        const rect = new Rect()
        rect.x = this.x - edge.left
        rect.y = this.y - edge.top
        rect.width = this.width + edge.left + edge.right
        rect.height = this.height + edge.top + edge.bottom

        return rect
    }
}
</code></pre><p>遍历子节点并执行完相关计算方法后，再将各个子节点的高度进行相加，得到父节点的高度。</p><h3 id="height-">height 属性</h3><p>默认情况下，节点的高度等于其内容的高度。但如果手动设置了 <code>height</code> 属性，则需要将节点的高度设为指定的高度：</p><pre><code class="language-ts">calculateBlockHeight() {
    // 如果元素设置了 height，则使用 height，否则使用 layoutBlockChildren() 计算出来的高度
    const height = this.styleNode?.values.height
    if (height) {
        this.dimensions.content.height = parseInt(height)
    }
}
</code></pre><p>为了简单起见，我们不需要实现<a href="https://link.zhihu.com/?target=https%3A//developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_box_model/Mastering_margin_collapsing" rel="nofollow noreferrer">外边距折叠</a>。</p><h3 id="--15">小结</h3><p>布局树是渲染引擎最复杂的部分，这一阶段结束后，我们就了解了布局树中每个盒子节点在页面中的具体位置和尺寸信息。下一步，就是如何把布局树渲染到页面上了。</p><h3 id="--16">绘制</h3><p>绘制阶段主要是根据布局树中各个节点的位置、尺寸信息将它们绘制到页面。目前大多数计算机使用光栅（raster，也称为位图）显示技术。将布局树各个节点绘制到页面的这个过程也被称为“光栅化”。</p><p>浏览器通常在图形API和库（如Skia、Cairo、Direct2D等）的帮助下实现光栅化。这些API提供绘制多边形、直线、曲线、渐变和文本的功能。</p><p>实际上绘制才是最难的部分，但是这一步我们有现成的 <a href="https://link.zhihu.com/?target=https%3A//github.com/Automattic/node-canvas" rel="nofollow noreferrer">canvas</a> 库可以用，不用自己实现一个光栅器，所以相对来说就变得简单了。在真正开始绘制阶段之前，我们先来学习一些关于计算机如何绘制图像、文本的基础知识，有助于我们理解光栅化的具体实现过程。</p><h3 id="--17">计算机如何绘制图像、文本</h3><p>在计算机底层进行像素绘制属于硬件操作，它依赖于屏幕和显卡接口的具体细节。为了简单起点，我们可以用一段内存区域来表示屏幕，内存的一个 bit 就代表了屏幕中的一个像素。比如在屏幕中的 <code>(x,y)</code> 坐标绘制一个像素，可以用 <code>memory[x + y * rowSize] = 1</code> 来表示。从屏幕左上角开始，列是从左至右开始计数，行是从上至下开始计数。因此屏幕最左上角的坐标是 <code>(0,0)</code>。</p><p>为了简单起见，我们用 1 bit 来表示屏幕的一个像素，0 代表白色，1 代表黑色。屏幕每一行的长度用变量 <code>rowSzie</code> 表示，每一列的高度用 <code>colSize</code> 表示。</p><figure class="kg-card kg-image-card"><img src="https://pic4.zhimg.com/80/v2-6e4622b6e30abe0a476676e106b8d027_1440w.webp" class="kg-image" alt="v2-6e4622b6e30abe0a476676e106b8d027_1440w" width="600" height="400" loading="lazy"></figure><h3 id="--18">绘制线条</h3><p>如果我们要在计算机上绘制一条直线，那么只要知道计算机的起点坐标 <code>(x1,y1)</code> 和终点坐标 <code>(x2,y2)</code> 就可以了。</p><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-4cb7322d209b50961a3979ee8e8e51bd_1440w.webp" class="kg-image" alt="v2-4cb7322d209b50961a3979ee8e8e51bd_1440w" width="600" height="400" loading="lazy"></figure><p>然后根据 <code>memory[x + y * rowSize] = 1</code> 公式，将 <code>(x1,y1)</code> 至 <code>(x2,y2)</code> 之间对应的内存区域置为 1，这样就画出来了一条直线。</p><h3 id="--19">绘制文本</h3><p>为了在屏幕上显示文本，首先必须将物理上基于像素点的屏幕，在逻辑上以字符为单位划分成若干区域，每个区域能输出单个完整的字符。假设有一个 256 行 512 列的屏幕，如果为每个字符分配一个 11*8 像素的网格，那么屏幕上总共能显示 23 行，每行 64 个字符（还有 3 行像素没使用）。</p><p>有了这些前提条件后，我们现在打算在屏幕上画一个 <code>A</code>：</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-887b0d213e83b3958eb78c87f4b5d644_1440w.webp" class="kg-image" alt="v2-887b0d213e83b3958eb78c87f4b5d644_1440w" width="600" height="400" loading="lazy"></figure><p>上图的 <code>A</code> 在内存区域中用 11*8 像素的网格表示。为了在内存区域中绘制它，我们可以用一个二维数组来表示它：</p><pre><code class="language-js">const charA = [
 [0, 0, 1, 1, 0, 0, 0, 0], // 按从左至右的顺序来读取 bit，转换成十进制数字就是 12
 [0, 1, 1, 1, 1, 0, 0, 0], // 30
 [1, 1, 0, 0, 1, 1, 0, 0], // 51
 [1, 1, 0, 0, 1, 1, 0, 0], // 51
 [1, 1, 1, 1, 1, 1, 0, 0], // 63
 [1, 1, 0, 0, 1, 1, 0, 0], // 51
 [1, 1, 0, 0, 1, 1, 0, 0], // 51
 [1, 1, 0, 0, 1, 1, 0, 0], // 51
 [1, 1, 0, 0, 1, 1, 0, 0], // 51
 [0, 0, 0, 0, 0, 0, 0, 0], // 0
 [0, 0, 0, 0, 0, 0, 0, 0], // 0
]
</code></pre><p>上面二维数组的第一项，代表了第一行内存区域每个 bit 的取值。一共 11 行，画出了一个字母 <code>A</code>。</p><p>如果我们为 26 个字母都建一个映射表，按 ascii 的编码来排序，那么 <code>charsMap[65]</code> 就代表字符 <code>A</code>，当用户在键盘上按下 <code>A</code> 键时，就把 <code>charsMap[65]</code> 对应的数据输出到内存区域上，这样屏幕上就显示了一个字符 <code>A</code>。</p><h3 id="--20">绘制布局树</h3><p>科普完关于绘制屏幕的基础知识后，我们现在正式开始绘制布局树（为了方便，我们使用 <a href="https://link.zhihu.com/?target=https%3A//github.com/Automattic/node-canvas" rel="nofollow noreferrer">node-canvas</a> 库）。</p><p>首先要遍历整个布局树，然后逐个节点进行绘制：</p><pre><code class="language-ts">function renderLayoutBox(layoutBox: LayoutBox, ctx: CanvasRenderingContext2D, parent?: LayoutBox) {
    renderBackground(layoutBox, ctx)
    renderBorder(layoutBox, ctx)
    renderText(layoutBox, ctx, parent)
    for (const child of layoutBox.children) {
        renderLayoutBox(child, ctx, layoutBox)
    }
}
</code></pre><p>这个函数对每个节点依次绘制背景色、边框、文本，然后再递归绘制所有子节点。</p><p>默认情况下，HTML 元素按照它们出现的顺序进行绘制。如果两个元素重叠，则后一个元素将绘制在前一个元素之上。这种排序反映在我们的布局树中，它将按照元素在 DOM 树中出现的顺序绘制元素。</p><h3 id="--21">绘制背景色</h3><pre><code class="language-ts">function renderBackground(layoutBox: LayoutBox, ctx: CanvasRenderingContext2D) {
    const { width, height, x, y } = layoutBox.dimensions.borderBox()
    ctx.fillStyle = getStyleValue(layoutBox, 'background')
    ctx.fillRect(x, y, width, height)
}
</code></pre><p>首先拿到布局节点的位置、尺寸信息，以 <code>x,y</code> 作为起点，绘制矩形区域。并且以 CSS 属性 <code>background</code> 的值作为背景色进行填充。</p><h3 id="--22">绘制边框</h3><pre><code class="language-ts">function renderBorder(layoutBox: LayoutBox, ctx: CanvasRenderingContext2D) {
    const { width, height, x, y } = layoutBox.dimensions.borderBox()
    const { left, top, right, bottom } = layoutBox.dimensions.border
    const borderColor = getStyleValue(layoutBox, 'border-color')
    if (!borderColor) return

    ctx.fillStyle = borderColor

    // left
    ctx.fillRect(x, y, left, height)
    // top
    ctx.fillRect(x, y, width, top)
    // right
    ctx.fillRect(x + width - right, y, right, height)
    // bottom
    ctx.fillRect(x, y + height - bottom, width, bottom)
}
</code></pre><p>绘制边框，其实我们绘制的是四个矩形，每一个矩形就是一条边框。</p><h3 id="--23">绘制文本</h3><pre><code class="language-ts">function renderText(layoutBox: LayoutBox, ctx: CanvasRenderingContext2D, parent?: LayoutBox) {
    if (layoutBox.styleNode?.node.nodeType === NodeType.Text) {
        // get AnonymousBlock x y
        const { x = 0, y = 0, width } = parent?.dimensions.content || {}
        const styles = layoutBox.styleNode?.values || {}
        const fontSize = styles['font-size'] || '14px'
        const fontFamily = styles['font-family'] || 'serif'
        const fontWeight = styles['font-weight'] || 'normal'
        const fontStyle = styles['font-style'] || 'normal'

        ctx.fillStyle = styles.color
        ctx.font = `${fontStyle} ${fontWeight} ${fontSize} ${fontFamily}`
        ctx.fillText(layoutBox.styleNode?.node.nodeValue, x, y + parseInt(fontSize), width)
    }
}
</code></pre><p>通过 canvas 的 <code>fillText()</code> 方法，我们可以很方便的绘制带有字体风格、大小、颜色的文本。</p><h3 id="--24">输出图片</h3><p>绘制完成后，我们可以借助 <code>canvas</code> 的 API 输出图片。下面用一个简单的示例来演示一下：</p><pre><code class="language-html">&lt;html&gt;
    &lt;body id=" body " data-index="1" style="color: red; background: yellow;"&gt;
        &lt;div&gt;
            &lt;div class="lightblue test"&gt;test1!&lt;/div&gt;
            &lt;div class="lightblue test"&gt;
                &lt;div class="foo"&gt;foo&lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/body&gt;
&lt;/html&gt;
* {
    display: block;
}

div {
    font-size: 14px;
    width: 400px;
    background: #fff;
    margin-bottom: 20px;
    display: block;
    background: lightblue;
}

.lightblue {
    font-size: 16px;
    display: block;
    width: 200px;
    height: 200px;
    background: blue;
    border-color: green;
    border: 10px;
}

.foo {
    width: 100px;
    height: 100px;
    background: red;
    color: yellow;
    margin-left: 50px;
}

body {
    display: block;
    font-size: 88px;
    color: #000;
}</code></pre><p>上面这段 HTML、CSS 代码经过渲染引擎程序解析后生成的图片如下：</p><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-57e893eb457caeba4ceb5b70a77b8889_1440w.webp" class="kg-image" alt="v2-57e893eb457caeba4ceb5b70a77b8889_1440w" width="600" height="400" loading="lazy"></figure><h3 id="--25">总结</h3><p>至此，这个玩具版的渲染引擎就完成了。虽然这个玩具并没有什么用，但如果能通过实现它来了解真实的渲染引擎是如何运作的，从这个角度来看，它还是“有用”的。</p><h3 id="--26">参考资料</h3><ul><li><a href="https://limpet.net/mbrubeck/2014/08/08/toy-layout-engine-1.html">Let's build a browser engine!</a></li><li><a href="https://github.com/mbrubeck/robinson">robinson</a></li><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/Performance/How_browsers_work">渲染页面：浏览器的工作原理</a></li><li><a href="https://link.zhihu.com/?target=https%3A//developer.mozilla.org/zh-CN/docs/Web/Performance/Critical_rendering_path" rel="nofollow noreferrer">关键渲染路径</a></li><li><a href="https://link.zhihu.com/?target=https%3A//book.douban.com/subject/1998341/" rel="nofollow noreferrer">计算机系统要素</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ CSS 单位指南：CSS em、rem、vh、vw 等详解 ]]>
                </title>
                <description>
                    <![CDATA[ 许多 CSS 属性如 width、margin、padding 和 font-size 都需要一个长度，而 CSS 有许多不同的方法来表达长度。 在 CSS 中，长度是一个数字，一个没有空格的单位。例如，5px、0.9em，等等。 在 CSS 中，一般有两种用于长度和尺寸的单位：绝对单位和相对单位。 绝对长度单位 绝对长度单位是基于一个实际的物理单位，通常被认为是跨设备的相同尺寸。但是，根据你的屏幕尺寸和质量，或者你的浏览器或操作系统的设置，可能会有一些例外。 下面是 CSS 中一些常见的绝对长度单位： px 像素，或 px，是 CSS 中最常见的长度单位之一。 在 CSS 中，1 像素被正式定义 [https://drafts.csswg.org/css-values/#reference-pixel]为 1/96 英寸。所有其他的绝对长度单位都是基于这个像素的定义。 但是，在最初制定这一标准时，大多数显示器的分辨率为 1024×768，DPI（每英寸点数）为 96。 现代设备的屏幕具有更高的分辨率和 DPI，所以 96 像素长的线可能无法精确测量到 1 英寸，这取决 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/css-unit-guide/</link>
                <guid isPermaLink="false">643bb68ef3f6f8067537b52a</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chengjun.L ]]>
                </dc:creator>
                <pubDate>Thu, 13 Apr 2023 02:29:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2023/04/5f9c9cd8740569d1a4ca347f.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/css-unit-guide/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">CSS Unit Guide: CSS em, rem, vh, vw, and more, Explained</a>
      </p><p>许多 CSS 属性如 <code>width</code>、<code>margin</code>、<code>padding</code> 和 <code>font-size</code> 都需要一个长度，而 CSS 有许多不同的方法来表达长度。</p><p>在 CSS 中，长度是一个数字，一个没有空格的单位。例如，<code>5px</code>、<code>0.9em</code>，等等。</p><p>在 CSS 中，一般有两种用于长度和尺寸的单位：绝对单位和相对单位。</p><h2 id="-">绝对长度单位</h2><p>绝对长度单位是基于一个实际的物理单位，通常被认为是跨设备的相同尺寸。但是，根据你的屏幕尺寸和质量，或者你的浏览器或操作系统的设置，可能会有一些例外。</p><p>下面是 CSS 中一些常见的绝对长度单位：</p><h3 id="px"><strong><code>px</code></strong></h3><p>像素，或 <code>px</code>，是 CSS 中最常见的长度单位之一。</p><p>在 CSS 中，1 像素被<a href="https://drafts.csswg.org/css-values/#reference-pixel">正式定义</a>为 1/96 英寸。所有其他的绝对长度单位都是基于这个像素的定义。</p><p>但是，在最初制定这一标准时，大多数显示器的分辨率为 1024×768，DPI（每英寸点数）为 96。</p><p>现代设备的屏幕具有更高的分辨率和 DPI，所以 96 像素长的线可能无法精确测量到 1 英寸，这取决于设备的情况。</p><p>尽管以像素为单位的尺寸在不同的设备上会有所不同，但一般认为在屏幕上使用像素更好。</p><p>如果你知道你的页面将在高质量的打印机上打印，那么你可以考虑使用另一个单位，比如 <code>cm</code> 或 <code>mm</code>。</p><p>你可以在<a href="https://www.smashingmagazine.com/2021/07/css-absolute-units/">这篇文章</a>中了解更多关于像素单位的历史，以及为什么 CSS 英寸并不总是与物理英寸相匹配。</p><h3 id="cm"><strong><code>cm</code></strong></h3><p>厘米</p><p>在 CSS 中，<code>1cm</code> 大约是 37.8 个像素，或约为 25.2/64 英寸。</p><h3 id="mm"><strong><code>mm</code></strong></h3><p>毫米</p><p>在 CSS 中，<code>1mm</code> 大约是 3.78 像素，或 1/10 厘米。</p><h3 id="in"><strong><code>in</code></strong></h3><p>英寸</p><p>在 CSS 中，1 英寸大约是 96 个像素，或大约 2.54 厘米。</p><h3 id="pt"><strong><code>pt</code></strong></h3><p>磅</p><p>在 CSS 中，<code>1pt</code> 大约是 1.3333 像素，或 1/72 英寸。</p><h3 id="pc"><strong><code>pc</code></strong></h3><p>派卡</p><p>在 CSS 中，<code>1pc</code> 大约是 16 个像素，或 1/6 英寸。</p><h2 id="--1">相对长度单位</h2><p>相对长度单位是相对于另一个元素的大小或设置。例如，一个元素的相对字体大小可以用父元素的字体大小来计算。</p><p>下面是一些常见的相对长度单位：</p><h3 id="em"><strong><code>em</code></strong></h3><p>CSS 的 <code>em</code> 单位的名字来自于一个排版单位。在字体排印学中，em 这个词“<a href="https://www.wikiwand.com/zh/Em_(%E5%AD%97%E4%BD%93%E6%8E%92%E5%8D%B0%E5%AD%A6)">最初是指所使用的字体和尺寸中大写字母 M 的宽度</a>”。</p><p>当与 <code>font-size</code> 属性一起使用时，<code>em</code> 继承其父元素的 <code>font-size</code> 大小：</p><pre><code class="language-css">.container {
  font-size: 16px;
}

.container p {
  font-size: 1em;
}

.container h2 {
  font-size: 3em;
}

.container h3 {
  font-size: 2em;
}
</code></pre><p>在这个例子中，<code>p</code> 的 <code>font-size</code> 是 <code>16px</code>（16 * 1）<em>。</em>同时，<code>h2</code> 的 <code>font-size</code> 为 <code>48px</code>（16 * 3），<code>h3</code> 为 <code>32px</code>（16 * 2）。</p><p>如果 <code>em</code> 与另一个属性（如 <code>width</code>）一起使用，<code>em</code> 是用目标元素的大小来计算的。</p><h3 id="rem"><strong><code>rem</code></strong></h3><p>根 <code>em</code>。这种相对单位不受父元素的大小或设置的影响，而是以文档的根为基础。对于网站来说，文档的根是 <code>html</code> 元素。</p><pre><code class="language-css">p {
  font-size: 1.25rem;
}
</code></pre><p>在大多数浏览器中，默认的字体大小是 16，所以 <code>html</code> 元素的 <code>font-size</code> 是 <code>16px</code>。所以在这种情况下，<code>p</code> 是 <code>20px</code>（16 * 1.25）。</p><p>但是如果用户改变了他们浏览器的默认字体大小，那么 <code>p</code> 的 <code>font-size</code> 就会相应地放大或缩小。</p><h3 id="--2"><strong><code>%</code></strong></h3><p>百分比，或相对于父级大小的百分比大小：</p><pre><code class="language-css">div {
  width: 400px;
}

div p {
  width: 75%;
}</code></pre><p>由于父级的宽度是 <code>400px</code>，所以内部段落的宽度是 <code>300px</code>（400 * .75）。</p><h3 id="vw"><strong><code>vw</code></strong></h3><p>视图宽度，<code>1vw</code> 是视口宽度的 1%。</p><p>比如说：</p><pre><code class="language-css">body {
  width: 100vw;
}
</code></pre><p>由于 <code>body</code> 元素被设置为 <code>100vw</code>，即视口宽度的 100%，所以它将占用它所能获得的全部宽度。因此，如果你把浏览器的大小调整为 690 像素宽，那么 <code>body</code> 就会占据所有 690 像素的宽度。</p><h3 id="vh"><strong><code>vh</code></strong></h3><p>视图高度，<code>1vh</code> 是视口高度的 1%。</p><p>例如：</p><pre><code class="language-css">div {
  height: 50vh;
}
</code></pre><p>该 <code>div</code> 将填充视口高度的 50%。因此，如果浏览器窗口的高度是 900 像素，那么该 <code>div</code> 的高度将是 450 像素。</p><h3 id="ex"><strong><code>ex</code></strong></h3><p>CSS <code>ex</code> 单位的名称来自于字体排印学中的 x-字高，即“<a href="https://www.wikiwand.com/zh/X%E5%AD%97%E9%AB%98">字体中字母 x 的高度</a>”。在许多字体中，小写的 x 字符通常是最大字符高度的一半。</p><p>在 CSS 中，<code>1ex</code> 是字体的 x-字高，或 <code>1em</code> 的一半。</p><p>但是，由于小写字母 x 的大小可以根据字体的不同而有很大的变化，因此 CSS 的 <code>ex</code> 单位很少被使用。</p><h3 id="ch"><strong><code>ch</code></strong></h3><p>字符单位，CSS 的 <code>ch</code> 单位被定义为字体的 0（零，或U+0030）字符的宽度。</p><p>虽然 <code>ch</code> 单位对于像 Courier 这样的单行线/固定宽度的字体来说是一种精确的测量，但对于像 Arial 这样的比例字体来说，它可能是不可预测的。</p><p>例如，如果你的字体是 Courier，而你把一个元素的宽度设置为 <code>60ch</code>，那么这个元素的宽度就正好是 60 个字符。</p><p>但是，如果你的字体是 Arial，而你把一个元素的宽度设置为 <code>60ch</code>，那么就不知道这个元素会有多宽——字符可能会溢出容器，也可能不够。</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2022/02/ch-unit-monospaced-and-proportional-fonts.png" class="kg-image" alt="An image showing 20ch as an exact measurement in Courier, but inexact in Helvetica and Georgia fonts." width="600" height="400" loading="lazy"><figcaption><a href="https://meyerweb.com/eric/thoughts/2018/06/28/what-is-the-css-ch-unit/" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 17.6px; vertical-align: baseline; background-color: transparent; color: var(--gray90); text-decoration: underline; cursor: pointer; word-break: break-word;">Source</a></figcaption></figure><p>请看<a href="https://meyerweb.com/eric/thoughts/2018/06/28/what-is-the-css-ch-unit/">这篇文章</a>，了解对 <code>ch</code> 单位的深入解释，并看一些例子。</p><h3 id="vmin-vmax"><code><strong>vmin</strong></code><strong> 和 </strong><code><strong>vmax</strong></code></h3><p>视口最小（<code>vmin</code>）和视口最大（<code>vmax</code>）的单位是基于 <code>vw</code> 和 <code>vh</code> 的值。</p><p><code>1vmin</code> 是视口最小尺寸的 1%，而 <code>1vmax</code> 是视口最大尺寸的 1%。</p><p>例如，想象一个宽 1200 像素、高 600 像素的浏览器窗口。在这种情况下，<code>1vmin</code> 是 <code>6px</code>（<code>vh</code> 的 1%，即 600 像素时较小值）。同时，<code>1vmax</code> 是 <code>12px</code>（<code>vh</code> 的 1%，即 1200 像素时的较大值）。</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 如何使用 CSS Font Weight 属性在 HTML 中加粗文本 ]]>
                </title>
                <description>
                    <![CDATA[ CSS 是 web 开发者的一个强大工具。它允许你以各种方式设置 HTML 内容的样式。 一种常见的格式化技术是使用 font-weight 属性将文本加粗。粗体字可以增加对关键信息的强调，创造视觉对比，并提高内容的可读性。 在这篇文章中，你将学习如何使用 CSS font-weight 属性在 HTML 中将文本加粗。无论你是初学者还是有经验的开发者，本文都将为你提供一个全面的指南，让你在 HTML 内容中使用 CSS 创建粗体文本。 理解 Font-Weight 属性 font-weight 属性是一个 CSS 属性，它决定了文本的粗细程度，数值越高表示字体越粗。 font-weight 属性接受各种数值，包括数字和关键字值。 数值范围从 100 到900，增量为 100。正常粗细的值是 400，而 700 的值被认为是粗体。一些常用的关键字值包括 bold、bolder、 lighter 和 normal。 如何用 CSS 创建粗体字 在 HTML 中使用 CSS 创建粗体字是一个简单的过程，可以通过几种方式实现。你可以选择使用任何形式的样式，如内联、内部或外部样式。 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/css-bold-how-to-bold-text-in-html-with-font-weight/</link>
                <guid isPermaLink="false">64216c6ce32a7606487d5982</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Miya Liu ]]>
                </dc:creator>
                <pubDate>Mon, 27 Mar 2023 04:29:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2023/03/kobu-agency-ipARHaxETRk-unsplash.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/css-bold-how-to-bold-text-in-html-with-font-weight/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">CSS Bold – How to Bold Text in HTML with Font Weight</a>
      </p><p>CSS 是 web 开发者的一个强大工具。它允许你以各种方式设置 HTML 内容的样式。</p><p>一种常见的格式化技术是使用 <code>font-weight</code> 属性将文本加粗。粗体字可以增加对关键信息的强调，创造视觉对比，并提高内容的可读性。</p><p>在这篇文章中，你将学习如何使用 CSS <code>font-weight</code> 属性在 HTML 中将文本加粗。无论你是初学者还是有经验的开发者，本文都将为你提供一个全面的指南，让你在 HTML 内容中使用 CSS 创建粗体文本。</p><h2 id="-font-weight-">理解 Font-Weight 属性</h2><p><code>font-weight</code> 属性是一个 CSS 属性，它决定了文本的粗细程度，数值越高表示字体越粗。</p><p><code>font-weight</code> 属性接受各种数值，包括数字和关键字值。</p><p>数值范围从 100 到900，增量为 100。正常粗细的值是 400，而 700 的值被认为是粗体。一些常用的关键字值包括 <code>bold</code>、<code>bolder</code>、<code>lighter</code> 和 <code>normal</code>。</p><h2 id="-css-">如何用 CSS 创建粗体字</h2><p>在 HTML 中使用 CSS 创建粗体字是一个简单的过程，可以通过几种方式实现。你可以选择使用任何形式的样式，如内联、内部或外部样式。</p><h3 id="-">如何用内联样式创建粗体字</h3><p>你可以使用内联样式，将 <code>font-weight</code> 属性直接应用于特定的 HTML 元素，就像这样：</p><pre><code class="language-html">&lt;p style="font-weight: bold;"&gt;This is a bold text&lt;/p&gt;
</code></pre><p>然而，内联样式会使你的 HTML 代码变得杂乱无章，难以维护，特别是当许多元素需要相同的样式时。</p><h3 id="--1">如何用内部样式创建粗体字</h3><p>内部样式设计允许你在 HTML 文档的 <code>head</code> 部分使用 <code>style</code> 标签来应用 CSS 样式，像这样：</p><pre><code class="language-html">&lt;head&gt;
  &lt;style&gt;
    p {
      font-weight: bold;
    }
  &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;p&gt;This is a bold text&lt;/p&gt;
&lt;/body&gt;
</code></pre><p>这种方法在对一个页面上的多个元素应用相同的样式时很有用。</p><h3 id="--2">如何用外部样式创建粗体字</h3><p>外部样式设计包括创建一个单独的 CSS 文件，并使用 <code>link</code> 标签将其链接到你的 HTML 文档中，像这样：</p><pre><code class="language-html">&lt;head&gt;
  &lt;link rel="stylesheet" type="text/css" href="styles.css"&gt;
&lt;/head&gt;
</code></pre><p>CSS 文件可以包含你网站上所有 HTML 元素的样式，你可以很容易地对这些样式进行修改，而不必修改 HTML 代码。</p><pre><code class="language-css">p {
  font-weight: bold;
}
</code></pre><h2 id="-html-">在 HTML 中使用粗体字的最佳实践</h2><p>虽然在 HTML 中使用粗体字可以帮助强调重要的信息，但必须遵循最佳实践，以确保文本的可读性和可访问性。</p><p>以下是在 HTML 中使用粗体字的一些最佳实践：</p><p><strong>选择正确的 font-weight：</strong>在使用粗体字时，必须选择正确的 font-weight，以确保文本清晰易读。</p><p>较粗的 font-weight 可能适合于标题，较细的字体可能更适合于正文。同样重要的是，要确保粗体字不会太过压抑，也不会影响到页面上的其他元素。</p><p><strong>平衡粗体字和其他格式化选项的关系：</strong>虽然粗体字可以成为吸引人们注意重要信息的有力方式，但重要的是要将它与其他格式选项相平衡，以创造视觉层次。</p><p>你可以使用其他样式，如斜体、下划线或不同的字体大小或颜色，来区分不同的重要程度。</p><p><strong>避免过度使用粗体字：</strong>过度使用粗体字会使文字更难阅读，并有损页面的整体设计。</p><p>重要的是要少用粗体字，只在有必要强调重要信息的地方使用。避免在整个段落或文本块中使用粗体字，因为这可能使读者难以区分重要信息和普通文本。</p><p><strong>测试无障碍性：</strong>当使用粗体字时，必须确保所有用户，包括有视力障碍的用户，都能使用。</p><p>屏幕阅读器可能难以阅读粗体文本，因此，使用无障碍工具测试页面，以确保粗体字格式正确，兼顾无障碍，是很重要的。</p><h2 id="--3"><strong>总结</strong></h2><p>总之，在 HTML 中使用粗体字可以有效地强调重要信息，并创造视觉层次。</p><p>通过选择合适的 font-weight，平衡粗体字与其他格式选项，避免过度使用，并进行无障碍测试，你可以确保粗体字保持可读性，并让所有用户都能使用。</p><p>谢谢你阅读本文，happy coding！</p><p>你可以<a href="https://joelolawanle.com/contents">访问我的网站</a>，阅读我的 188 篇文章。你也可以使用搜索栏来查看我是否写过特定的文章。</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 如何使用 CSS 组合器来选择和样式元素 ]]>
                </title>
                <description>
                    <![CDATA[ 组合器允许你将多个选择器组合起来，以选择 DOM 中的特定元素。在这篇文章中，我将用实例来解释四个组合器。 在我上一篇关于 CSS 选择器类型 [https://www.freecodecamp.org/chinese/news/how-to-select-elements-to-style-in-css/] 的文章中，我分享了七种类型的选择器，用于选择你想要为其设置样式的元素。 如果你还没有看过那篇文章，我建议你在阅读这篇文章之前先读一读它。 在本教程中，我讲的是组合器，它允许你使用多种选择器类型来选择元素。这种选择是基于符合指定的多个选择器类型的元素之间的关系。 如果你喜欢的话，这篇文章还有一个视频版本 [https://www.youtube.com/watch?v=ZKRRUUPl8SA]。 下面是 CSS 中的四个组合器以及它们的工作原理。 如何使用后代组合器 这个组合器允许你选择一个元素，它是另一个元素的后代。这里的“后代”可以是孩子、孙子、曾孙、曾曾曾......等等。 要使用这个组合器，你要在选择器之间输入一个空格，像这样： .container p { ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/css-combinators-to-select-elements/</link>
                <guid isPermaLink="false">63c5592f42d274071ebbee2a</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chengjun.L ]]>
                </dc:creator>
                <pubDate>Mon, 09 Jan 2023 09:22:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2023/01/image--4-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/css-combinators-to-select-elements/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Use CSS Combinators to Select and Style Elements</a>
      </p><p>组合器允许你将多个选择器组合起来，以选择 DOM 中的特定元素。在这篇文章中，我将用实例来解释四个组合器。</p><p>在我上一篇关于 <a href="https://www.freecodecamp.org/chinese/news/how-to-select-elements-to-style-in-css/">CSS 选择器类型</a>的文章中，我分享了七种类型的选择器，用于选择你想要为其设置样式的元素。</p><p>如果你还没有看过那篇文章，我建议你在阅读这篇文章之前先读一读它。</p><p>在本教程中，我讲的是<strong>组合器</strong>，它允许你使用多种选择器类型来选择元素。这种选择是基于符合指定的多个选择器类型的元素之间的关系。</p><p>如果你喜欢的话，这篇文章还有一个<a href="https://www.youtube.com/watch?v=ZKRRUUPl8SA">视频版本</a>。</p><p>下面是 CSS 中的四个组合器以及它们的工作原理。</p><h2 id="-">如何使用后代组合器</h2><p>这个组合器允许你选择一个元素，它是另一个元素的后代。这里的“后代”可以是孩子、孙子、曾孙、曾曾曾......等等。</p><p>要使用这个组合器，你要在选择器之间输入一个<strong>空格</strong>，像这样：</p><pre><code class="language-css">.container p {
  color: red;
}
</code></pre><p>上面这个样式声明选择了 <code>p</code> 元素，这些元素是具有 <strong>div </strong>class<strong> </strong>的元素的后代。</p><p>它在 HTML 中是这样的：</p><pre><code class="language-html">&lt;p&gt;I am the first p&lt;/p&gt;

&lt;div class='container'&gt;
    &lt;p&gt;I am the second p&lt;/p&gt;
    
    &lt;div&gt;
        &lt;p&gt;I am the third p&lt;/p&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;I am the last p&lt;/p&gt;
</code></pre><p>结果如下：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-396.png" class="kg-image" alt="image-396" width="600" height="400" loading="lazy"></figure><p>从上面的结果中，你可以看到第二个和第三个 <code>p</code> 被设置了样式。这是因为它们都是 <code>.container</code> 元素的后代。第二个 <code>p</code> 是直接子元素，而第三个 <code>p</code> 是孙子元素（<code>div</code> 的直接子元素），但它们都是后代。</p><p>你也可以像这样使用多个选择器：</p><pre><code class="language-css">.container div p {
  color: red;
}
</code></pre><p>结果如下：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-405.png" class="kg-image" alt="image-405" width="600" height="400" loading="lazy"></figure><p>正如你所看到的，只有第三个 <code>p</code> 被设置了样式，因为这个元素是 <code>div</code> 元素的后代，而 <code>div</code> 又是具有 <strong><strong>container</strong> </strong>class 的元素的后代。</p><h2 id="--1">如何使用子代组合器</h2><p>子代组合器匹配子代、孙代，以此类推。子代组合器选择的元素是另一个元素的直接子代。</p><p>你在选择器之间使用<strong>大于</strong>符号（&gt;）来指定一个选择器是另一个的直接子代。</p><p>下面是一个例子：</p><pre><code class="language-css">.container &gt; p {
  color: red;
}
</code></pre><p>这个样式将选择所有作为 <strong><strong>container</strong></strong> class 元素的直接子元素的 <code>p</code> 元素。让我们看看这在上面的 HTML 例子中是如何运行的：</p><pre><code class="language-html">&lt;p&gt;I am the first p&lt;/p&gt;

&lt;div class='container'&gt;
    &lt;p&gt;I am the second p&lt;/p&gt;
    
    &lt;div&gt;
        &lt;p&gt;I am the third p&lt;/p&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;I am the last p&lt;/p&gt;
</code></pre><p>结果如下：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-397.png" class="kg-image" alt="image-397" width="600" height="400" loading="lazy"></figure><p>正如你在这里看到的，只有第二个 <code>p</code> 受到影响。尽管第二个和第三个 <code>p</code> 元素是 <strong><strong>container</strong></strong> class 元素的后代，但只有第二个是直接子元素，正如我们在 CSS 中所指定的那样。</p><p>你也可以像这样用这个组合器使用多个选择器：</p><pre><code class="language-css">.container &gt; div &gt; p {
  color: red;
}
</code></pre><p>这种样式设计将匹配所有 <code>p</code> 元素，这些元素是 <code>div</code> 元素的直接子代，而 <code>div</code> 元素又是 <strong><strong>container</strong></strong> class 元素的直接子代。</p><h2 id="--2">如何使用相邻兄弟组合器</h2><p>我们已经看过了后代，那么兄弟姐妹呢——就像在一个家庭环境中一样？在选择器之间使用的相邻兄弟组合器，可以匹配作为另一个元素的兄弟的元素。</p><p>要使用这个组合器，你要输入 ~ 符号。下面是一个例子：</p><pre><code class="language-css">div ~ p {
  color: red;
}
</code></pre><p>这种样式设计选择了所有与 <code>div</code> 元素同级的 <code>p</code> 元素。比方说，我们有以下的 HTML：</p><pre><code class="language-html">&lt;p&gt;I am the first p&lt;/p&gt;

&lt;div class='container'&gt;
    &lt;p&gt;I am the second p&lt;/p&gt;
    
    &lt;div&gt;
        &lt;p&gt;I am the third p&lt;/p&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;I am the last p&lt;/p&gt;
&lt;p&gt;I am the very last p&lt;/p&gt;
</code></pre><p>结果如下：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-399.png" class="kg-image" alt="image-399" width="600" height="400" loading="lazy"></figure><p>最后两个 <code>p</code> 有颜色样式。这是因为 <code>div</code>（具有 <strong><strong>container</strong></strong> class）和这些 <code>p</code> 是兄弟元素。</p><p>然而，如果你注意到，第一个 <code>p</code> 也是该 <code>div</code> 的兄弟元素。那么为什么它没有被设置样式呢？</p><p>原因是，在我们的 CSS 中，我们是这样使用子代组合器的：</p><pre><code class="language-css">div ~ p
</code></pre><p>这个选择意味着它只选择 <code>div</code> 元素<strong>后面</strong>的 <code>p</code> 兄弟元素。之前的兄弟元素不受影响。</p><p>如果选择变为：</p><pre><code class="language-css">p ~ div
</code></pre><p>然后它将选择在 <code>p</code> 元素<strong>之后</strong>的 <code>div</code> 的同级元素。</p><h2 id="--3">如何使用相邻组合器</h2><p>这个组合器与兄弟组合器类似。不同的是，兄弟组合器匹配一个元素之后的所有兄弟元素，而相邻组合器只匹配一个元素之后的紧接着的兄弟元素。</p><p>要使用这个组合器，你要使用 + 符号，像这样：</p><pre><code class="language-css">div + p {
  color: red;
}
</code></pre><p>这种样式会影响到作为 <code>div</code> 元素之后的即时兄弟元素，即 <code>p</code> 元素。比方说，我们有前面的 HTML 例子：</p><pre><code class="language-html">&lt;p&gt;I am the first p&lt;/p&gt;

&lt;div class='container'&gt;
    &lt;p&gt;I am the second p&lt;/p&gt;
    
    &lt;div&gt;
        &lt;p&gt;I am the third p&lt;/p&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;I am the last p&lt;/p&gt;
&lt;p&gt;I am the very last p&lt;/p&gt;
</code></pre><p>结果如下：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-400.png" class="kg-image" alt="image-400" width="600" height="400" loading="lazy"></figure><p>从这个结果中，你可以看到，只有第四个 <code>p</code> 元素被设置了样式。这是因为在我们的 HTML 代码中，这个 <code>p</code> 元素是 <code>div</code> 元素之后的一个紧接着的兄弟元素。</p><p>尽管最后一个 <code>p</code> 也是 <code>div</code> 元素之后的同级元素，但它并不是 <code>div</code> 的相邻元素。</p><h2 id="--4">总结</h2><p>正如我们在这篇文章中所看到的，组合器允许你使用多种选择器类型。根据 DOM 中与这些选择器相匹配的元素之间的关系，你可以针对元素进行样式设计。</p><p>我们看到的组合器有：</p><ul><li><strong>后代组合器</strong>：用于选择属于其他元素的后代元素</li><li><strong>子代组合器</strong>：用于选择属于其他元素的直接子代元素</li><li><strong>兄弟组合器</strong>：用于选择在其他元素之后的兄弟元素</li><li><strong>相邻组合器</strong>：用于选择其他元素之后的紧接着的兄弟元素</li></ul><p>如果你喜欢这篇文章并从中受益，请和其他人分享它 💜</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ CSS display:none 和 visibility:hidden 的区别 ]]>
                </title>
                <description>
                    <![CDATA[ display:none 和 visibility:hidden 是 CSS 中的两个样式声明，你可以用它们来隐藏屏幕上的元素。但它们之间有什么区别呢？ 在构建应用程序时，有些时候你想在视觉上隐藏元素（不是从 DOM 中删除它们，只是在屏幕上）。你可以用不同的方法来做这件事。 两种常见的方法包括使用值为 none 的 display 属性或值为 hidden 的 visibility 属性。 尽管这两种方法都在视觉上隐藏了元素，但它们使元素响应的方式不同。我将在本文中解释这些差异。 如果你有兴趣，这里有本文的视频版本 [https://youtu.be/nMq3U65wAdQ]。 我将通过下面的例子来解释这一切是如何进行。 HTML： <div class="container">   <div class="block1"></div>   <div class="block2"></div>   <div class="block3"></div> </div> CSS： .container {   padding: 20px;   width: max-co ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/css-display-none-and-visibility-hidden-the-difference/</link>
                <guid isPermaLink="false">63bc0d3f81727e076314601a</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chengjun.L ]]>
                </dc:creator>
                <pubDate>Thu, 05 Jan 2023 12:19:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2023/01/11.-display-visibility-2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/css-display-none-and-visibility-hidden-the-difference/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">CSS display:none and visibility:hidden – What's the Difference?</a>
      </p><p><code>display:none</code> 和 <code>visibility:hidden</code> 是 CSS 中的两个样式声明，你可以用它们来隐藏屏幕上的元素。但它们之间有什么区别呢？</p><p>在构建应用程序时，有些时候你想在视觉上隐藏元素（不是从 DOM 中删除它们，只是在屏幕上）。你可以用不同的方法来做这件事。</p><p>两种常见的方法包括使用值为 none 的 <code>display</code> 属性或值为 hidden 的 <code>visibility</code> 属性。</p><p>尽管这两种方法都在视觉上隐藏了元素，但它们使元素响应的方式不同。我将在本文中解释这些差异。</p><p>如果你有兴趣，这里有本文的<a href="https://youtu.be/nMq3U65wAdQ">视频版本</a>。</p><p>我将通过下面的例子来解释这一切是如何进行。</p><p>HTML：</p><pre><code class="language-html">&lt;div class="container"&gt;
  &lt;div class="block1"&gt;&lt;/div&gt;
  &lt;div class="block2"&gt;&lt;/div&gt;
  &lt;div class="block3"&gt;&lt;/div&gt;
&lt;/div&gt;
</code></pre><p>CSS：</p><pre><code class="language-css">.container {
  padding: 20px;
  width: max-content;
  display: flex;
  border: 1px solid black;
}

.block1,
.block2,
.block3 {
  height: 40px;
  width: 120px;
}

.block1 {
  background-color: rgb(224, 110, 49);
  margin-right: 20px;
}

.block2 {
  background-color: rgb(77, 77, 234);
  margin-right: 20px;
}

.block3 {
  background-color: rgb(12, 154, 142);
}
</code></pre><p>我们有一个 class 为 <strong>container</strong> 的 <code>div</code>。这个 <code>div</code> 有三个子 <code>div</code>，其 class 分别为 <strong>block1</strong>、<strong>block2</strong> 和 <strong>block3</strong>。我们已经为这些 <code>div</code> 指定了一些样式。第一个 <code>div</code> 子代是 <code>orange</code>，第二个是 <code>blue</code>，第三个是 <code>teal</code>。</p><p>结果如下：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/12/image-77.png" class="kg-image" alt="image-77" width="600" height="400" loading="lazy"></figure><h2 id="-css-display-none"><strong>如何在 CSS 中使用 <code>display: none</code></strong></h2><p><code>display</code> 属性设置了一个元素的显示方式（如 <strong>inline</strong> 或 <strong>block</strong>），也决定了一个元素的子元素的布局（如<strong> flex</strong>、<strong>grid </strong>等等）。</p><p>如果该属性的值为 <strong>none</strong>，那么该元素的显示就被关闭了。这意味着该元素——以及它的子元素——将不会被显示。文档在没有该元素的情况下被渲染，就像它不存在一样。</p><p>现在让我们看看 <code>display: none</code> 是如何工作的。下面是一个将此样式应用于 <strong>.block2</strong> 元素的例子：</p><pre><code class="language-css">.block2 {
  background-color: rgb(77, 77, 234);
  margin-right: 20px;
  display: none;
}
</code></pre><p>结果如下：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/12/image-78.png" class="kg-image" alt="image-78" width="600" height="400" loading="lazy"></figure><p>正如你在这里看到的，<strong>.container </strong>元素的宽度已经减少。这就像 <strong>.block2</strong> 元素不存在一样。因为我们在这个元素上使用了 <code>display:none</code>，它在文档中没有被渲染。所以它在屏幕上的空间被其他元素占据。</p><p>我们也可以通过在 <strong>.block1</strong> 元素上添加 <code>display:none</code> 来测试这一点：</p><pre><code class="language-css">.block1 {
  background-color: rgb(224, 110, 49);
  margin-right: 20px;
  display: none;
}

.block2 {
  background-color: rgb(77, 77, 234);
  margin-right: 20px;
  display: none;
}
</code></pre><p>结果如下：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/12/image-79.png" class="kg-image" alt="image-79" width="600" height="400" loading="lazy"></figure><p>这里你看到 <strong>.block1 </strong>和 <strong>.block2 </strong>没有被渲染，所以它们的空间被占用。</p><h2 id="-css-visibility-hidden"><strong>如何在 CSS 中使用 <code>visibility: hidden</code></strong></h2><p><code>visibility</code> 属性，顾名思义，指定了一个元素是否可见。但是，这个属性并不影响元素的布局。这是与 <code>layout</code> 属性相比的主要区别。</p><p>如果这个属性的值是 <strong><strong>hidden</strong></strong>，它所应用的元素就会变得不可见。元素的<a href="https://youtu.be/opHpcJIUbEU">盒子模型</a>所需的空间保持不变，但元素本身被隐藏。</p><p>让我们看看这个属性如何被应用于我们上面的例子。下面是这个样式应用于 <strong>.block2</strong> 元素的结果：</p><pre><code class="language-css">.block2 {
  background-color: rgb(77, 77, 234);
  margin-right: 20px;
  visibility: hidden;
}
</code></pre><p>结果如下：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/12/image-80.png" class="kg-image" alt="image-80" width="600" height="400" loading="lazy"></figure><p>正如你在这里注意到的，与 <code>display: none</code> 不同，<strong>.block2 </strong>元素是不可见的，但其布局保持不变。事实上，这个元素上的 <code>margin-right</code> 仍然存在。只有这个元素本身被隐藏了。</p><p>让我们也给 <strong>.block1 </strong>添加这个样式，看看结果如何：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/12/image-81.png" class="kg-image" alt="image-81" width="600" height="400" loading="lazy"></figure><p>现在这两个元素都是不可见的，但它们仍然在文档中被渲染，所以它们的空间并没有空出来。</p><p>接下来你可能会想，“<code>visibility: hidden</code> 和 <code>opacity: 0</code> 之间有什么区别呢？”</p><h2 id="visibility-hidden-vs-opacity-0"><strong><code>visibility: hidden</code> vs <code>opacity: 0</code></strong></h2><p>这两种样式看起来非常相似。我可以通过在我们上面的例子中把 <code>visibility:hidden</code> 替换为 <code>opacity:0</code> 来告诉你：</p><pre><code class="language-css">.block1 {
  background-color: rgb(224, 110, 49);
  margin-right: 20px;
  opacity: 0;
}

.block2 {
  background-color: rgb(77, 77, 234);
  margin-right: 20px;
  opacity: 0;
}
</code></pre><p>结果如下：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/12/image-82.png" class="kg-image" alt="image-82" width="600" height="400" loading="lazy"></figure><p>你可以看到，这个结果和之前的结果在视觉上没有区别。但在元素的行为上是有区别的。</p><p>具有 <code>visibility: hidden</code> 的元素是<strong>不可交互</strong>的。我不知道这是不是最好的说法，但我的意思是，用户不能与这样的元素互动（例如，通过点击）。这是因为这种元素确实是不可见的。</p><p>具有 <code>opacity: 0</code> 的元素是可以互动的，因为它们实际上是可见的，只是非常透明。<code>opacity</code> 属性并不指定一个元素的可见性——它只指定透明度。</p><p>我们可以用一个例子来验证这个区别。假设 <strong>.block2</strong> 元素有一个这样的 <code>onclick</code> 属性：</p><pre><code class="language-html">&lt;div class="block2" onclick="alert('hello')"&gt;&lt;/div&gt;
</code></pre><p>如果你在这个元素上使用 <code>visibility:hidden</code>，点击这个元素所在的空间将不会触发什么。但如果你在这个元素上使用 <code>opacity:0</code>，点击同样的空间将触发警报模式，显示 “hello” 文本。你可以在你的浏览器上测试一下，实际看看这个效果。</p><h2 id="display-none-visibility-hidden-"><strong><code>display:none</code> 和 <code>visibility:hidden</code> 的使用示例</strong></h2><p>这些样式声明可以根据你想实现什么被用于不同的场景。</p><p>在我的经验中，当我想隐藏一些内容时，我使用 <code>display:none</code>。想想隐藏一个弹出框、UI 上已经被选中的待办事项，或者页面上的侧边栏。</p><p>对内容使用 <code>visibility:hidden</code> 会导致内容的空间被保留，当页面上有空白区域时，会显得有些奇怪。</p><p>我唯一使用 <code>visibility:hidden</code> 的时候是当我想在“隐藏”或“显示”一个元素时显示一些动画。<code>display</code> 属性不会在数值之间产生动画，但 <code>visibility</code> 属性可以。我将 <code>visibility</code> 与 <code>opacity</code> 结合起来使用，以实现这种淡入和淡出的动画。</p><h2 id="-"><strong>总结</strong></h2><p>概括地说，<code>display:none</code>、<code>visibility:hidden</code> 和 <code>opacity:0</code> 可以被用来视觉上隐藏元素，但是：</p><ul><li><code>display:none</code> 关闭元素的布局，所以元素不被渲染</li><li><code>visibility:hidden</code> 隐藏元素，而不改变它们的布局</li><li><code>opacity:0</code> 使元素非常透明，但是用户依然可以和元素交互</li></ul><p>如果你喜欢这篇文章，请将它分享给其他学习者。😇</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ CSS 按钮样式——悬停、颜色和背景 ]]>
                </title>
                <description>
                    <![CDATA[ 在这篇文章中，你将看到如何使用 CSS 来设置一个按钮的样式。 我在这里的目的主要是展示不同的 CSS 规则和样式是如何应用和使用的。我们不会看到太多的设计灵感，也不会讨论样式设计的想法。 相反，这将更多地是对样式本身如何工作、哪些属性是常用的以及它们如何被组合的概述。 你将首先看到如何在 HTML 中创建一个按钮。然后你将学习如何覆盖按钮的默认样式。最后，你将看到如何为按钮的三种不同状态设计样式。 目录  1.  在 HTML 中创建一个按钮  2.  改变按钮的默认样式  3.  改变背景颜色  4.  改变文本颜色  5.  改变边框样式  6.  改变大小  7.  设置按钮状态的样式  8.  设置悬停状态的样式  9.  设置聚焦状态的样式  ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/css-button-style-hover-color-and-background/</link>
                <guid isPermaLink="false">63bb94af81727e0763145e20</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chengjun.L ]]>
                </dc:creator>
                <pubDate>Tue, 03 Jan 2023 04:19:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2023/01/moises-de-paula-HPZZHJ-LuDI-unsplash.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/css-button-style-hover-color-and-background/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">CSS Button Style – Hover, Color, and Background</a>
      </p><p>在这篇文章中，你将看到如何使用 CSS 来设置一个按钮的样式。</p><p>我在这里的目的主要是展示不同的 CSS 规则和样式是如何应用和使用的。我们不会看到太多的设计灵感，也不会讨论样式设计的想法。</p><p>相反，这将更多地是对样式本身如何工作、哪些属性是常用的以及它们如何被组合的概述。</p><p>你将首先看到如何在 HTML 中创建一个按钮。然后你将学习如何覆盖按钮的默认样式。最后，你将看到如何为按钮的三种不同状态设计样式。</p><h1 id="-"><strong>目录</strong></h1><ol><li>在 HTML 中创建一个按钮</li><li>改变按钮的默认样式</li><li>改变背景颜色</li><li>改变文本颜色</li><li>改变边框样式</li><li>改变大小</li><li>设置按钮状态的样式</li><li>设置悬停状态的样式</li><li>设置聚焦状态的样式</li><li>设置激活状态的样式</li><li>总结</li></ol><p>我们开始吧！</p><h2 id="-html-"><strong>如何</strong>在 HTML 中创建一个按钮</h2><p>要创建一个按钮，需要使用 <code>&lt;button&gt;</code> 元素。</p><p>与使用一般的容器相比，这是一个更容易理解和更加语义化的选择，因为它是用 <code>&lt;div&gt;</code> 元素创建的。</p><p>在下面的 <code>index.html</code> 文件中，我已经创建了一个网页的基本结构，并添加了一个单一的按钮：</p><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
    &lt;link rel="stylesheet" href="style.css"&gt;
    &lt;title&gt;CSS Button Style&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;button type="button" class="button"&gt;Click me!&lt;/button&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre><p>让我们分解 <code>&lt;button type="button" class="button"&gt;Click me!&lt;/button&gt;</code> 这行代码：</p><ul><li>你首先添加按钮元素，它由一个开始 <code>&lt;button&gt;</code> 标签和结束 <code>&lt;/button&gt;</code> 标签组成。</li><li><code>&lt;button&gt;</code> 开始标签中的 <code>type="button"</code> 属性明确地创建了一个可点击的按钮。由于这个特殊的按钮不是用来提交表单的，为了语义上的原因，添加它是很有用的，可以使代码更清晰，不会触发任何不需要的动作。</li><li><code>class="button"</code> 属性将用于在一个单独的 CSS 文件中对按钮进行样式设置。值 <code>button</code> 可以是你选择的任何其他名称。例如，你可以使用 <code>class="btn"</code>。</li><li>文本 <code>Click me!</code> 是按钮内部可见的文本。</li></ul><p>任何将被应用于按钮的样式将被放在 <code>spearate style.css</code> 文件中。</p><p>你可以通过将这两个文件连接起来，将样式应用到 HTML 内容中。你可以通过标签 <code>&lt;link rel="stylesheet" href="style.css"&gt;</code> 来实现，这个标签在 <code>index.html</code> 中使用。</p><p>在 <code>style.css</code> 文件中，我添加了一些样式，只把按钮放在浏览器窗口的中间位置。</p><p>注意，<code>class="button"</code> 是和 <code>.button</code> 选择器一起使用的。这是一种将样式直接应用于按钮的方法。</p><pre><code class="language-css">* {
    box-sizing: border-box;
} 

body {
    display:flex;
    justify-content: center;
    align-items: center;
    margin:50px auto;
}

.button {
    position: absolute;
    top:50%
}
</code></pre><p>上面的代码将产生以下结果：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/02/Screenshot-2022-02-06-at-10.29.02-PM.png" class="kg-image" alt="Screenshot-2022-02-06-at-10.29.02-PM" width="600" height="400" loading="lazy"></figure><p>按钮的默认样式会根据你所使用的浏览器而有所不同。</p><p>这是一个例子，说明在谷歌 Chrome 浏览器上按钮的原始样式是怎样的。</p><h2 id="--1">如何改变按钮的默认样式</h2><h3 id="--2">如何改变按钮的背景颜色</h3><p>要改变按钮的背景颜色，可以使用 CSS 的 <code>background-color</code> 属性，给它一个你喜欢的颜色值。</p><p>在 <code>.button</code> 选择器中，你可以使用 <code>background-color:#0a0a23;</code> 来改变按钮的背景颜色。</p><pre><code class="language-css">.button {
    position: absolute;
    top:50%;
    background-color:#0a0a23;
}
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/02/Screenshot-2022-02-06-at-10.28.30-PM.png" class="kg-image" alt="Screenshot-2022-02-06-at-10.28.30-PM" width="600" height="400" loading="lazy"></figure><h3 id="--3">如何改变按钮的文本颜色</h3><p>文字的默认颜色是黑色，所以当你添加一个深色的背景颜色时，你会发现文字已经消失了。</p><p>另一件要确保的事情是，按钮的背景颜色和文本颜色之间有足够的对比。这有助于使文字更易读，更容易被人看清。</p><p>接下来，使用 <code>color</code> 属性来改变文本的颜色：</p><pre><code class="language-css">.button {
    position: absolute;
    top:50%;
    background-color:#0a0a23;
    color: #fff;
}
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/02/Screenshot-2022-02-06-at-10.28.03-PM.png" class="kg-image" alt="Screenshot-2022-02-06-at-10.28.03-PM" width="600" height="400" loading="lazy"></figure><h3 id="--4">如何改变按钮的边框风格</h3><p>注意到按钮边缘的灰色吗？那是按钮边框的默认颜色。</p><p>解决这个问题的一个方法是使用 <code>border-color</code> 属性。你将其值设置为与 <code>background-color</code> 的值相同。这样就可以确保边框的颜色与按钮的背景相同。</p><p>另一种方法是通过使用 <code>border:none;</code> 来完全移除按钮周围的边框。</p><pre><code class="language-css">.button {
  position: absolute;
  top:50%;
  background-color:#0a0a23;
  color: #fff;
  border:none;
}
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/02/Screenshot-2022-02-06-at-10.27.33-PM.png" class="kg-image" alt="Screenshot-2022-02-06-at-10.27.33-PM" width="600" height="400" loading="lazy"></figure><p>接下来，你也可以通过使用 <code>border-radius</code> 属性将按钮的边缘变圆，就像这样：</p><pre><code class="language-css">.button {
    position: absolute;
    top:50%;
    background-color:#0a0a23;
    color: #fff;
    border:none;
    border-radius:10px;
  }
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/02/Screenshot-2022-02-06-at-10.26.57-PM.png" class="kg-image" alt="Screenshot-2022-02-06-at-10.26.57-PM" width="600" height="400" loading="lazy"></figure><p>你也可以通过使用 <code>box-shadow</code> 属性在按钮周围添加一个轻微的暗影效果：</p><pre><code class="language-css"> position: absolute;
    top:50%;
    background-color:#0a0a23;
    color: #fff;
    border:none;
    border-radius:10px;
    box-shadow: 0px 0px 2px 2px rgb(0,0,0);
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/02/Screenshot-2022-02-06-at-10.25.55-PM.png" class="kg-image" alt="Screenshot-2022-02-06-at-10.25.55-PM" width="600" height="400" loading="lazy"></figure><h3 id="--5">如何改变按钮的大小</h3><p>在按钮的边框内创造更多空间的方法是增加按钮的 <code>padding</code>。</p><p>下面我为按钮的顶部、底部、右侧和左侧的 padding 添加了 15px 的值。</p><p>我还分别用 <code>min-height</code> 和 <code>min-width</code> 属性设置了一个最小高度和宽度。按钮需要足够大，适合所有不同类型的设备。</p><pre><code class="language-css">.button {
    position: absolute;
    top:50%;
    background-color:#0a0a23;
    color: #fff;
    border:none; 
    border-radius:10px; 
    padding:15px;
    min-height:30px; 
    min-width: 120px;
  }
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/02/Screenshot-2022-02-06-at-10.42.58-PM.png" class="kg-image" alt="Screenshot-2022-02-06-at-10.42.58-PM" width="600" height="400" loading="lazy"></figure><h2 id="--6"><strong>如何</strong>设置按钮状态的样式</h2><p>按钮有三种不同的状态：</p><ul><li><code>:hover</code></li><li><code>:focus</code></li><li><code>:active</code></li></ul><p>这三种状态的风格最好是不同的，不要共享相同的风格。</p><p>在下面的章节中，我将简要解释每个状态的含义和触发它们的原因。你也会看到一些你可以为每个单独的状态设计按钮的方式。</p><h3 id="-hover-">如何设计 <code>:hover</code> 状态的样式</h3><p><code>:hover</code> 状态是用户将鼠标或触控板移到一个按钮上，而不选择它或点击它。</p><p>要改变按钮在悬停时的样式，请使用 <code>:hover</code> CSS 伪类选择器。</p><p>使用 <code>:hover</code> 的一个常见变化是改变按钮的背景颜色。</p><p>为了使这种变化不那么突然，可以将 <code>:hover</code> 与 <code>transition</code> 属性搭配使用。</p><p><code>transition</code> 属性将有助于使从无状态到 <code>:hover</code> 状态的过渡更加平滑。</p><p>背景颜色的变化会比没有 <code>transition</code> 属性时慢一些。这也将有助于使最终结果对用户不那么突兀。</p><pre><code class="language-css">.button:hover {
      background-color:#002ead;
      transition: 0.7s;
  }
</code></pre><p>在上面的例子中，我使用了一个 Hex 颜色代码值，使我在悬停在按钮上时的背景颜色变得更浅。</p><p>在 <code>transition</code> 属性的帮助下，当从无状态过渡到 <code>:hover</code> 状态时，我还造成了 <code>0.7s</code> 的延迟。这使得从原来的 <code>#0a0a23</code> 背景色过渡到 <code>#002ead</code> 背景色的速度变慢。</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/02/hover-2.gif" class="kg-image" alt="hover" width="600" height="400" loading="lazy"></figure><p>请记住，<code>:hover</code> 伪类对移动设备屏幕和移动应用程序不起作用。只选择在桌面网络应用中使用悬停效果，而不是触屏。</p><h3 id="-focus-">如何设计 <strong><code>:focus</code></strong> 状态的样式</h3><p><code>:focus</code> 状态对键盘用户有用——具体来说，当你通过点击 <code>Tab</code> 键（<code>⇥</code>）来选中一个按钮时，它会被激活。</p><p>当你按下 <code>Tab</code> 键后聚焦在按钮上，你会看到以下情况：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/02/focus-5.gif" class="kg-image" alt="focus-5" width="600" height="400" loading="lazy"></figure><p>注意到当按钮获得焦点时，它周围轻微的浅蓝色轮廓吗？</p><p>浏览器对 <code>:focus</code> 伪类有默认的样式设计，是为了方便键盘导航。完全去掉这个 <code>outline</code> 轮廓并不是一个好主意。</p><p>然而，你可以为它创建自定义样式，并使它容易被发现。</p><p>这样做的一个方法是，首先将轮廓的颜色设置为 <code>transparent</code>。</p><p>之后，你可以将轮廓样式 <code>outline-style</code> 保持为 <code>solid</code>。最后，使用 <code>box-shadow</code> 属性，你可以在元素被聚焦时添加一个你喜欢的颜色：</p><pre><code class="language-css"> .button:focus {
    outline-color: transparent;
    outline-style:solid;
    box-shadow: 0 0 0 4px #5a01a7;
}
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/02/focusend.gif" class="kg-image" alt="focusend" width="600" height="400" loading="lazy"></figure><p>你还可以根据你想达到的效果，再次将这些样式与 <code>transition</code> 属性一起使用：</p><pre><code class="language-css">  .button:focus {
    outline-color: transparent;
    outline-style:solid;
    box-shadow: 0 0 0 4px #5a01a7;
    transition: 0.7s;
}
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/02/focusend1.gif" class="kg-image" alt="focusend1" width="600" height="400" loading="lazy"></figure><h3 id="-active-">如何设计 <strong><code>:active</code></strong> 状态的样式</h3><p>当你通过点击电脑的鼠标或按下笔记本的触控板来点击按钮时，<code>:active</code> 状态会被激活。</p><p>那么，在我应用并保持了 <code>:hover</code> 和 <code>:focus</code> 状态的样式后，看看当我点击按钮时会发生什么：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/02/active-1.gif" class="kg-image" alt="active-1" width="600" height="400" loading="lazy"></figure><p>当我把鼠标悬停在按钮上时，<code>:hover</code> 状态的样式会在点击前应用。</p><p><code>:focus</code> 状态的样式也会被应用，因为当一个按钮被点击的时候，它也会获得一个 <code>:focus</code> 状态和一个 <code>:active</code> 状态。</p><p>然而，请记住，它们并不是一回事。</p><p><code>:focus</code> 状态是指当一个元素被选中时，而 <code>:active</code> 是指当用户通过按住并按下一个元素来点击它。</p><p>要改变用户点击按钮时的样式，可以将样式应用到 <code>:active</code> CSS 伪选择器上。</p><p>在这个例子中，我改变了用户点击按钮时的背景颜色。</p><pre><code class="language-css">.button:active {
    background-color: #ffbf00;
}
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/02/activefinal.gif" class="kg-image" alt="activefinal" width="600" height="400" loading="lazy"></figure><h2 id="--7">总结</h2><p>你现在知道了用 CSS 设置按钮样式的基本知识。</p><p>我们讨论了如何改变按钮的背景颜色和文本颜色，以及如何为按钮的不同状态设计样式。</p><p>要了解更多关于 web 设计的知识，请查看 freeCodeCamp 的<a href="https://www.freecodecamp.org/chinese/learn/2022/responsive-web-design">响应式 web 设计认证课程</a>。在交互式课程中，你将通过创建 15 个练习项目和 5 个认证项目来学习 HTML 和 CSS。</p><p>请注意，上述认证仍处于测试阶段——如果你想要最新的稳定版本，请查看<a href="https://www.freecodecamp.org/chinese/learn/responsive-web-design/">这里</a>。</p><p>谢谢你阅读本文，happy coding！</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ CSS 选择器类型——如何在 CSS 中选择元素以设置样式 ]]>
                </title>
                <description>
                    <![CDATA[ 当你想用 CSS 给一个元素添加样式时，你首先要“选择”它。在这篇文章中，我将向你展示七种方法。 以下是在 CSS 中为元素设置样式的语法： selector {   /* 在这里设置样式 */ } 你有一个选择器，“瞄准”你想为其设计样式的元素，然后你有一个开放的大括号。大括号之后的样式使用不同的 CSS 属性，然后你用一个闭合的大括号来关闭它。 有许多方法来定位元素。你可以把这些方法称为选择器类型。 如果你喜欢视频的话，这里有一个关于在 CSS 中选择元素样式的方法 [https://www.youtube.com/watch?v=0yysG5U_2i8] 的视频。 下面是 CSS 中的七种选择器类型。 如何在 CSS 中使用通用选择器（*） 通用选择器，即星号（*），允许你选择任何类型的所有元素进行样式设计。下面是一个例子： * {   border: 1px solid black; } 比方说，我们对下面的 HTML 使用这种样式： <body>     <h1>CSS styles</h1>  ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/how-to-select-elements-to-style-in-css/</link>
                <guid isPermaLink="false">63b39d19836d320782be181e</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Miya Liu ]]>
                </dc:creator>
                <pubDate>Tue, 03 Jan 2023 03:22:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2023/01/css-selector-types.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/how-to-select-elements-to-style-in-css/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">CSS Selector Types – How to Select Elements to Style in CSS</a>
      </p><p>当你想用 CSS 给一个元素添加样式时，你首先要“选择”它。在这篇文章中，我将向你展示七种方法。</p><p>以下是在 CSS 中为元素设置样式的语法：</p><pre><code class="language-css">selector {
  /* 在这里设置样式 */
}
</code></pre><p>你有一个选择器，“瞄准”你想为其设计样式的元素，然后你有一个开放的大括号。大括号之后的样式使用不同的 CSS 属性，然后你用一个闭合的大括号来关闭它。</p><p>有许多方法来定位元素。你可以把这些方法称为<strong>选择器类型</strong>。</p><p>如果你喜欢视频的话，这里有一个关于<a href="https://www.youtube.com/watch?v=0yysG5U_2i8">在 CSS 中选择元素样式的方法</a>的视频。</p><p>下面是 CSS 中的七种选择器类型。</p><h2 id="-css-">如何在 CSS 中使用通用选择器（*）</h2><p>通用选择器，即星号（*），允许你选择任何类型的所有元素进行样式设计。下面是一个例子：</p><pre><code class="language-css">* {
  border: 1px solid black;
}
</code></pre><p>比方说，我们对下面的 HTML 使用这种样式：</p><pre><code class="language-html">&lt;body&gt;
    &lt;h1&gt;CSS styles&lt;/h1&gt;
    &lt;p&gt;How to apply styles&lt;/p&gt;
    &lt;div&gt;
        &lt;img width="20px" height="20px" src="https://www.freecodecamp.org/news/content/images/size/w150/2022/03/deee.jpg" /&gt;
    &lt;/div&gt;
&lt;/body&gt;
</code></pre><p>结果如下：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/image--3-.png" class="kg-image" alt="image--3-" width="600" height="400" loading="lazy"></figure><p>你可以看到 <code>body</code>、<code>h1</code>、<code>p</code>、<code>div</code> 和 <code>img</code> 元素的 <code>border</code> 都是 <strong><strong>1px solid black</strong></strong>，因为我们使用了通用选择器。</p><h2 id="-css--1">如何在 CSS 中通过标签名称为元素设置样式</h2><p>你也可以通过使用标签名称来选择元素为其设置样式。下面是一个例子：</p><pre><code class="language-css">p {
  color: red;
}

img {
  width: 100px;
  height: 100px;
}
</code></pre><p>这些样式声明对所有 <code>p</code> 元素应用 <code>color</code> 为红色（<strong>red</strong>），对所有 <code>img</code> 元素应用 <strong>200px</strong> 的宽度（<code>width</code>）和高度（<code>height</code>）。</p><p>这是上面的样式如何在这个 HTML 中实现：</p><pre><code class="language-html">&lt;span&gt;I am a span&lt;/span&gt;
&lt;p&gt;There is a span above me&lt;/p&gt;
&lt;img src="https://www.freecodecamp.org/news/content/images/size/w150/2022/03/deee.jpg" /&gt;
</code></pre><p>结果：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-383.png" class="kg-image" alt="image-383" width="600" height="400" loading="lazy"></figure><p>你可以看到 <code>span</code> 没有被设置样式，只有 <code>img</code> 和 <code>p</code> 被设置了样式。</p><h2 id="-css--2">如何为 CSS 中的类设置样式</h2><p>元素接受不同的属性，包括类。你可以根据你在一个元素上指定的类来定位该元素。下面是一个例子：</p><pre><code class="language-html">&lt;div class="container"&gt;
    &lt;h2&gt;Hello&lt;/h2&gt;
&lt;/div&gt;

&lt;div&gt;
    &lt;h2&gt;How are you&lt;/h2&gt;
&lt;/div&gt;
</code></pre><p>这里有两个 <code>div</code>，但只有一个具有 <strong><strong>container</strong></strong> 类的属性。你可以用<strong>句号</strong>（<strong><strong>.</strong></strong>）加上类来设置样式，像这样：</p><pre><code class="language-css">div {
  border: 1px solid purple;
}

.container {
  border-width: 20px;
}
</code></pre><p>结果如下：</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/09/image--5-.png" class="kg-image" alt="image--5-" width="600" height="400" loading="lazy"></figure><p>从 CSS 中，我们指定所有的 <code>div</code> 元素都应该有一个 <code>border</code> 为 <strong><strong>1px solid purple</strong></strong>。但是对于有 <strong><strong>container</strong> </strong><code>class</code> 的元素，你可以从结果中看到它的 <code>border-width</code> 是 20px。</p><h2 id="-css-id-">如何在 CSS 中为 Id 设置样式</h2><p>与 <code>class</code> 属性类似，你可以在一个元素上指定一个 <code>id</code>，你可以在 CSS 中对其进行样式设置。</p><p>下面是一个例子：</p><pre><code class="language-html">&lt;div class="container"&gt;
    &lt;h2&gt;Hello&lt;/h2&gt;
&lt;/div&gt;

&lt;div id="container"&gt;
    &lt;h2&gt;How are you&lt;/h2&gt;
&lt;/div&gt;
</code></pre><p>你可以通过使用哈希（#）加上 id 来定位 <code>id</code> 元素，像这样：</p><pre><code class="language-css">#container {
  border-left: 10px solid blue;
}
</code></pre><p>结果如下：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-385.png" class="kg-image" alt="image-385" width="600" height="400" loading="lazy"></figure><p>使用具有 <strong><strong>container</strong></strong> <code>id</code> 的元素（无论是 <code>div</code>、<code>p</code> 还是任何类型），我们只对第二个 <code>div</code> 元素应用样式。</p><p>然而，与类不同，<code>id</code> 必须是<strong>唯一的</strong>。两个或更多的元素不能有相同的 <code>id</code>，因为这将导致意外的行为。</p><h2 id="-css--3">如何给 CSS 中的其他属性设置样式</h2><p>我们已经看到了如何选择 <code>class</code> 和 <code>id</code> 属性。如果你想选择其他属性呢？你可以使用方括号（<strong>[attr]</strong>）。应该怎么做呢？</p><p>让我们看一个例子：</p><pre><code class="language-html">&lt;a href="#"&gt;
    Some link
&lt;/a&gt;

&lt;p href="https://google.com"&gt;
    A paragraph link
&lt;/p&gt;
</code></pre><p>在这个例子中，我们有两个元素：一个 <code>a</code> 标签和一个 <code>p</code> 标签。要为这两个元素设计样式，你可以直接使用它们的标签名：</p><pre><code class="language-css">p, a {
  color: red;
}
</code></pre><p>逗号允许你一次对多个选择器应用样式。</p><p>但另一种可以为这两个元素设置样式的方法是使用它们的属性。它们都有一个 <code>href</code> 属性。</p><p>请记住，<code>p</code> 标签中不支持 <code>href</code> 属性，我只是用它来说明一个例子。</p><p>下面是你如何使用 <code>href</code> 属性为这两个元素设置样式：</p><pre><code class="language-css">[href] {
  color: red;
}
</code></pre><p>这个 CSS 将匹配所有带有 <code>href</code> 属性的元素。</p><p>下面是结果：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-386.png" class="kg-image" alt="image-386" width="600" height="400" loading="lazy"></figure><p>这两个元素都有 <code>href</code> 属性，所以它们都被选中设置样式。在这里，我们使用了没有值的 <code>href</code> 属性。你也可以指定一个值来具体说明你的目标，就像这样：</p><pre><code class="language-css">[href="#"] {
  color: red;
}
</code></pre><p>结果是这样的：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-387.png" class="kg-image" alt="image-387" width="600" height="400" loading="lazy"></figure><p>只有 <code>a</code> 标签有带 # 值的 <code>href</code> 属性，所以这是唯一符合我们的样式的元素，你可以从上面的图片中看到。</p><h2 id="-css--4">如何在 CSS 中使用伪类</h2><p>伪类是一种选择器类型，它允许你在特定的状态下选择元素。仅举几个例子，以下是一些支持的状态：</p><ul><li><code>hover</code>（当鼠标浮在一个元素上时）</li><li><code>disabled</code>（当一个元素如输入或按钮被禁用时）</li><li><code>required</code>（当一个表单元素是必需时）</li></ul><p>还有很多，你可以在<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes">伪类 MDN 文档</a>中找到。</p><p>你可以在元素处于这些状态时应用样式。你可以通过使用<strong>冒号</strong>（<strong>:</strong>）跟在状态后面来选择状态。下面是一个例子：</p><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;button&gt;
    Hover me
&lt;/button&gt;
</code></pre><p><code>&lt;!DOCTYPE html&gt;</code> 一行是很重要的，它指定了它是 HTML5，所以伪类可以生效。</p><p>这里是 CSS：</p><pre><code class="language-css">:hover {
  background-color: black;
  color: white;
}
</code></pre><p>这个 CSS 将把这些样式应用到你悬停的任何元素上，结果如下：</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-388.png" class="kg-image" alt="image-388" width="600" height="400" loading="lazy"></figure><p>左边的图片是没有悬停状态的。在右边，你可以看到应用在 <code>body</code> 和 <code>button</code> 上的样式，因为我们正在它们上面悬停。</p><p>通过悬停在 <code>button</code> 上，你也在悬停在 <code>body</code> 上，因为 <code>button</code> 是 <code>body</code> 的一个子节点。</p><h2 id="-css--5">如何使用 CSS 中的伪元素选择器</h2><p>伪元素（不同于伪类）是用来选择“一个元素的特定部分”的。不是整个元素——只是一个部分。你也可以用它们来为一个现有的元素添加伪（人造）元素。</p><p>这里有一篇关于 <a href="https://dillionmegida.com/p/pseudo-elements-vs-pseudo-classes-in-css/">CSS 中的伪元素与伪类</a>的详细文章。</p><p>下面是一些支持的伪元素选择器：</p><ul><li><code>selection</code>：一个元素的高亮部分</li><li><code>first-line</code>：一个段落的第一行</li><li><code>placeholder</code>：一个输入元素的占位符文本</li></ul><p>还有很多，你可以在 <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements">MDN 的伪元素文档</a>中找到。</p><p>要使用伪元素选择器来应用样式，你可以使用<strong>双冒号</strong>（<strong><strong>::</strong></strong>）加上伪元素。下面是一个例子：</p><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;input placeholder="Enter some text" /&gt;
</code></pre><p>下面是这个 HTML 的 CSS：</p><pre><code class="language-css">input {
  color: blue;
}

::placeholder {
  color: red;
  font-style: italic;
}
</code></pre><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-389.png" class="kg-image" alt="image-389" width="600" height="400" loading="lazy"></figure><p><code>::placeholder</code> 伪元素选择器为所有表单元素的“占位符部分”设置样式。正如你在上面的例子中看到的，<code>input</code> 元素本身的 <code>color</code> 样式是 <strong><strong>blue</strong></strong>，但占位符部分的样式不同。</p><h2 id="-">总结</h2><p>在这篇文章中，我已经向你展示了七种方法，你可以为你选择的元素设计样式。我们看到了：</p><ul><li>通用选择器，用于选择所有元素</li><li>标签名称，用于选择符合标签名称的元素</li><li>类，用于选择带有类属性的元素</li><li>id 用于选择有 id 属性的元素</li><li>属性用于选择有或没有指定值的属性的元素</li><li>伪类用于选择特定状态下的元素</li><li>伪元素用于选择元素的特定部分</li></ul><p>你也可以把这些选择器结合起来，使你想定位的元素更加具体。你可以使用<strong>组合器</strong>（<strong><strong>Combinators</strong></strong>）来实现这一点。</p><p>组合器允许你使用多个选择器，根据符合选择器的元素之间的关系来定位元素。如果你想了解更多，这里有一篇我写的<a href="https://www.freecodecamp.org/chinese/news/css-combinators-to-select-elements/">关于组合器的文章</a>。</p><p>给你一个快速预览——组合器是在多个选择器类型之间使用的，它们允许你根据元素与其他元素的关系来设计样式。</p><p>谢谢你阅读本文！</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 详解 CSS 伪类之 :is 伪类 ]]>
                </title>
                <description>
                    <![CDATA[ 伪类允许你在一个特定的状态下对一个元素进行样式设计。在 CSS 中，有许多支持状态的类。在这篇文章中，我将解释 :is 伪类是如何工作的。 这篇文章是我在未来几周和几个月内要做的一个新系列的第一篇文章：详解 CSS 伪类。我打算尽可能地解释更多的伪类，每篇独立的文章都会涉及到一个特定的伪类。 我有一个介绍 CSS 伪类的 YouTube 播放列表 [https://www.youtube.com/playlist?list=PLLdz3KlabJv2sYL287Q_8lpy_jOgwQjN2] ，你也可以去看看。 注意：伪类与伪元素不同。伪类适用于元素的不同状态，而伪元素适用于一个元素的不同部分。 你可以在这里了解到更多的区别 [https://dillionmegida.com/p/pseudo-elements-vs-pseudo-classes-in-css/]。 在本教程中，你将学习 :is 伪类的所有基础知识。 :is 伪类是如何工作的 :is 伪类接受一个选择器参数的列表，并匹配所有适用于该列表中任何选择器的元素。以下是语法： :is(selector1, s ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/css-is-pseudo-class-explained/</link>
                <guid isPermaLink="false">63b2e8b8836d320782be1734</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Miya Liu ]]>
                </dc:creator>
                <pubDate>Fri, 30 Dec 2022 14:22:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2023/01/1.-is--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/css-is-pseudo-class-explained/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">CSS Pseudo-Classes – How the :is Pseudo-Class Works with Examples</a>
      </p><p>伪类允许你在一个特定的状态下对一个元素进行样式设计。在 CSS 中，有许多支持状态的类。在这篇文章中，我将解释 <code>:is</code> 伪类是如何工作的。</p><p>这篇文章是我在未来几周和几个月内要做的一个新系列的第一篇文章：<strong>详解 CSS 伪类</strong>。我打算尽可能地解释更多的伪类，每篇独立的文章都会涉及到一个特定的伪类。</p><p>我有一个<a href="https://www.youtube.com/playlist?list=PLLdz3KlabJv2sYL287Q_8lpy_jOgwQjN2">介绍 CSS 伪类的 YouTube 播放列表</a>，你也可以去看看。</p><p>注意：伪类与伪元素不同。伪类适用于元素的不同状态，而伪元素适用于一个元素的不同部分。</p><p>你可以在这里了解到<a href="https://dillionmegida.com/p/pseudo-elements-vs-pseudo-classes-in-css/">更多的区别</a>。</p><p>在本教程中，你将学习 <code>:is</code> 伪类的所有基础知识。</p><h2 id="-is-">:is 伪类是如何工作的</h2><p><code>:is</code> 伪类接受一个选择器参数的列表，并匹配所有适用于该列表中任何选择器的元素。以下是语法：</p><pre><code class="language-css">:is(selector1, selector2, selector3) {
  /* 样式 */
}
</code></pre><p>你可以指定任何类型的选择器，DOM 中任何与选择器相匹配的元素都会被选中并进行样式处理。</p><p>我有一篇关于 <a href="https://www.freecodecamp.org/chinese/news/how-to-select-elements-to-style-in-css/">CSS 中的选择器类型</a>的文章，你可以查看一下你可以在 <code>:is</code> 伪类中使用的不同选择器。</p><p>你唯一不能与该类一起使用的选择器类型是<strong>伪元素</strong>。</p><p>另外，因为我喜欢我的文章有视频版本（对于那些可能喜欢/喜欢看视频的人），你可以在 YouTube 上查看 <code>:is</code> 伪类的视频版本。</p><p>让我们看看这个伪类的一些例子。</p><h3 id="-is--1">:is 伪类的例子</h3><p>看看这个 CSS 代码：</p><pre><code class="language-css">:is(.selector1, #selector2, selector3, :selector4, [selector5]) {
  /* 样式 */
}
</code></pre><p>作为参数列表，我们有 <strong>selector1</strong> <code>class</code>、<strong>selector2</strong> <code>id</code>、<strong>selector3</strong> <code>tag</code>、<strong>selector4</strong> <code>pseudo-class</code> 和 <strong>selector5</strong> <code>attribute</code> 选择器。DOM 中的所有元素，只要与这些选择器中的至少一个相匹配，就会被选中进行样式设计。</p><p>让我们看看一个实际的例子：</p><pre><code class="language-html">&lt;section&gt;
  &lt;p&gt;Paragraph of section&lt;/p&gt;
&lt;/section&gt;

&lt;div&gt;
  &lt;p&gt;Paragraph of div&lt;/p&gt;
&lt;/div&gt;

&lt;article&gt;
  &lt;p&gt;Paragraph of article&lt;/p&gt;
&lt;/article&gt;

&lt;span&gt;
  &lt;p&gt;Paragraph of span&lt;/p&gt;
&lt;/span&gt;
</code></pre><p>这里，我们有一个 <code>section</code>、<code>div</code>、<code>article</code> 和一个 <code>span</code> 元素。这些元素中的每一个都有一个 <code>p</code> 子元素。如果我们想给这些元素的所有 <code>p</code> 子元素设置样式，我们可以有以下的样式声明：</p><pre><code class="language-css">section p,
div p,
article p,
span p {
  text-decoration: underline;
  color: red;
}
</code></pre><p>结果：</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/11/image-107.png" class="kg-image" alt="image-107" width="600" height="400" loading="lazy"></figure><p>但我们可以用 <code>:is</code> 伪类来改进 CSS，方法如下：</p><pre><code class="language-css">:is(section, div, article, span) p {
  text-decoration: underline;
  color: red;
}
</code></pre><p>这让我们得到了与上面相同的结果。但有什么不同呢？</p><p>在 <code>:is</code> 伪类中，我们传递了四个选择器：标签名称 <code>selection</code>、<code>div</code>、<code>article</code> 和 <code>span</code>。使用后代选择器（一个空格字符），我们选择作为列表中任何一个选择器的后代的 <code>p</code> 标签元素。这意味着，这个选择将选择：</p><ul><li>section 的 <code>p</code> 子元素</li><li>div 的 <code>p</code> 子元素</li><li><code>article</code> 的 <code>p</code> 子元素</li><li><code>span</code> 的 <code>p</code> 子元素</li></ul><p>使用 <code>:is</code> 伪类，我们缩短了元素选择器。</p><p>让我们看看另一个例子。</p><pre><code class="language-html">&lt;button&gt;Click Me&lt;/button&gt;
&lt;!-- &lt;button class="active"&gt;Click Me&lt;/button&gt; --&gt;
</code></pre><p>对于这个按钮，假设你想在它处于 <code>hover</code> 或 <code>focus</code> 状态时，或在它有一个 <code>active</code> 类时，应用同样的样式。通常情况下，你可以有以下代码：</p><pre><code class="language-css">button:hover,
button:focus,
button.active {
  background-color: black;
  color: white;
}
</code></pre><p>结果是：</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/11/image-108.png" class="kg-image" alt="image-108" width="600" height="400" loading="lazy"></figure><p>你也可以用 <code>:is</code> 伪类来改进这一点：</p><pre><code class="language-css">button:is(:hover, :focus, .active) {
  background-color: black;
  color: white;
}
</code></pre><p>在这里，你看到我们在按钮上添加了 <code>:is</code> 伪类，而对于选择器，我们有：</p><ul><li><code>:hover</code> 伪类</li><li><code>:focus</code> 伪类</li><li><code>.active</code> 类</li></ul><p>这将相应地匹配按钮。</p><h2 id="-is--2">:is 不支持伪元素</h2><p>正如我前面提到的，你可以将不同类型的选择器作为参数传递给 <code>:is</code> 伪类，但伪元素除外。</p><p>例如：</p><pre><code class="language-css">:is(::after, ::selection) {
  /* 样式 */
}
</code></pre><p>在这里，我们把 <code>::after</code> 和 <code>::selection</code> 伪元素作为参数传递给 <code>:is</code> 伪类。这样的样式声明是行不通的。</p><h2 id="-">什么是容错选择器列表</h2><p>当你在 CSS 中把多个选择器组合在一起，而其中一个选择器不被支持（或无效），你的样式声明将被忽略，举个例子：</p><pre><code class="language-css">.button, #box, invalid {
  /* 样式 */
}
</code></pre><p>对于我们上面的样式，我们有 <strong><strong>.button</strong></strong> <code>class</code>、<strong>#box</strong> <code>id</code> 和 <strong><strong>invalid</strong></strong> <code>tag</code> 选择器。第一个和第二个选择器是有效的，但没有像 <strong>invalid</strong> 这样的标签名称。因为第三个不被支持，整个样式将被忽略。</p><p>但是 <code>:is</code> 伪类允许有一个容错选择器列表（forgiving selector list）的概念。这意味着，如果作为参数传递的选择器之一不被支持，那将被“宽恕”。也就是说，支持的选择器将被应用，目标元素也会相应地被设置样式，例如：</p><pre><code class="language-css">button:is(:hover, :focuss, .active) {
  background-color: black;
  color: white;
}
</code></pre><p>在这里，我们为我们的样式传递 <strong><strong>:hover</strong></strong> <code>pseudo-class</code>、<strong><strong>:focuss</strong></strong> <code>pseudo-class</code> 和 <strong><strong>.active</strong></strong> <code>class</code>。:focuss 伪类不被支持，但不是整个样式声明被忽略，<strong>:hover</strong> 和 <strong>.active</strong> 选择器仍将被应用。</p><h2 id="--1">总结</h2><p>你可以用 <code>:is</code> 伪类做很多高级选择。这个类允许你用更短、更容易阅读的方式来写长的选择器。</p><p>在这篇文章中，我们已经了解了 <code>:is</code> 伪类。通过例子，我们看到了它是如何工作的，以及它是如何使 CSS 代码变得更好的。</p><p>请记住，这个伪类的工作原理与 <code>:where</code> 伪类类似，但有一个主要区别。我将在以后的文章中解释 <code>:is</code> 和 <code>:where</code> 伪类的区别。</p><p>如果你喜欢这篇文章，请将它分享给更多人。😇</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 如何用 CSS 和 JavaScript 制作一个自定义的鼠标光标 ]]>
                </title>
                <description>
                    <![CDATA[ 你是否曾经访问过一个网站，并为其功能感到惊讶？其中一个可能是一个很酷的鼠标光标，与你习惯的常规箭头或指针光标不同。 这确实可以改善用户体验，最近我一直在想它是如何工作的。所以我开始做一些研究，我发现了它是如何做到的。 在这篇文章中，我将解释如何制作一个自定义的鼠标指针。在本文结束时，你将学会如何用两种不同的方法制作这些光标，即使用 CSS 和 JavaScript。然后，你将准备好用不同的创意光标来美化你的网站，以增加互动性。准备好了吗？让我们开始吧。 前提 本文对初学者友好，但要理解一些概念，你应该具备以下基本知识：  * HTML  * 基本的 CSS  * 基本的 JavaScript 如何用 CSS 定制鼠标光标 用 CSS 来定制鼠标指针是非常简单的，因为 CSS 已经有一个属性来处理这个问题。我们所要做的就是识别这个属性并使用它。 作为前端工程师，我们经常使用这个属性，它就是万能的 cursor 属性。是的，这个属性让我们有能力制作一个自定义游标。 在我们去看一个实际的例子之前，让我们先看看与 CSS cursor 属性相关的值。虽然大多数开发者只使用了几个重 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/how-to-make-a-custom-mouse-cursor-with-css-and-javascript/</link>
                <guid isPermaLink="false">638472cc832e3f07817634de</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Miya Liu ]]>
                </dc:creator>
                <pubDate>Thu, 24 Nov 2022 08:50:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2022/11/salman-hossain-saif-m3xjTe9zl6k-unsplash.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/how-to-make-a-custom-mouse-cursor-with-css-and-javascript/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Make a Custom Mouse Cursor with CSS and JavaScript</a>
      </p><p>你是否曾经访问过一个网站，并为其功能感到惊讶？其中一个可能是一个很酷的鼠标光标，与你习惯的常规箭头或指针光标不同。</p><p>这确实可以改善用户体验，最近我一直在想它是如何工作的。所以我开始做一些研究，我发现了它是如何做到的。</p><p>在这篇文章中，我将解释如何制作一个自定义的鼠标指针。在本文结束时，你将学会如何用两种不同的方法制作这些光标，即使用 CSS 和 JavaScript。然后，你将准备好用不同的创意光标来美化你的网站，以增加互动性。准备好了吗？让我们开始吧。</p><h2 id="-"><strong>前提</strong></h2><p>本文对初学者友好，但要理解一些概念，你应该具备以下基本知识：</p><ul><li>HTML</li><li>基本的 CSS</li><li>基本的 JavaScript</li></ul><h2 id="-css-">如何用 CSS 定制鼠标光标</h2><p>用 CSS 来定制鼠标指针是非常简单的，因为 CSS 已经有一个属性来处理这个问题。我们所要做的就是识别这个属性并使用它。</p><p>作为前端工程师，我们经常使用这个属性，它就是万能的 <code>cursor</code> 属性。是的，这个属性让我们有能力制作一个自定义游标。</p><p>在我们去看一个实际的例子之前，让我们先看看与 CSS <code>cursor</code> 属性相关的值。虽然大多数开发者只使用了几个重要的值，但还有更多的值是我们应该看的。</p><figure class="kg-card kg-embed-card kg-card-hascaption"><iframe id="cp_embed_XWeBEXo" src="https://codepen.io/developeraspire5/embed/preview/XWeBEXo?default-tabs=css%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=XWeBEXo" title="CSS Cursors" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe><figcaption>所有 CSS 光标的可视化展示</figcaption></figure><p>从上面的代码片断和结果来看，你可以通过将鼠标光标悬停在包含每个 CSS <code>cursor</code> 属性值名称的那些方框上，看到并测试出 CSS 的不同鼠标光标。</p><p>现在，我如何使用 CSS 来定制鼠标光标？要使用这个方法，你只需要告诉 CSS 你打算用什么图片，并使用 <code>url</code> 值将 <code>cursor</code> 属性指向图片的 URL。</p><pre><code class="language-css">body {
  cursor: url('image-path.png'),auto;
}</code></pre><p>从上面的代码片段中，你可以看到我在文档主体上设置了这个，所以无论光标在哪里移动，它都可以适用于光标。它有在 <code>url()</code> 中指定的图像。</p><p>该属性的下一个值是一个后备值，以备图片无法加载或由于一些内部故障而无法找到。我相信你不希望你的网站“没有光标“，所以添加一个回退是非常重要的。你也可以根据需求添加尽可能多的后备 URL。</p><pre><code class="language-css">body {
  cursor: url('image-path.png'), url('image-path-2.svg), 
          url('image-path-3.jpeg'), auto;
}</code></pre><p>你也可以在你的网页的某个特定元素或部分上定制光标。下面是一个 CodePen 的例子：</p><figure class="kg-card kg-embed-card kg-card-hascaption"><iframe id="cp_embed_GRMBxWN" src="https://codepen.io/developeraspire5/embed/preview/GRMBxWN?default-tabs=css%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=GRMBxWN" title="Custom cusors on specific element." scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe><figcaption>在网页的不同元素上使用不同的自定义光标</figcaption></figure><p>这就是在 CSS 中定制光标的全部内容。现在让我们来看看如何在 JavaScript 中做到这一点。</p><h2 id="-javascript-">如何用 JavaScript 制作自定义鼠标光标</h2><p>为了用 JavaScript 实现这一点，你需要操作 DOM 来获得所需的结果。</p><p>首先，让我们看看 HTML：</p><h3 id="html"><strong>HTML</strong></h3><pre><code class="language-html">&lt;div class="cursor rounded"&gt;&lt;/div&gt;
&lt;div class="cursor pointed"&gt;&lt;div&gt;</code></pre><p>从上面的代码片段中，我创建了两个 <code>div</code> 来表示光标。我们的计划是通过 JavaScript 来操作这些 div，这样它们在网页上的移动就会被 JavaScript 的 <code>mousemove</code> 事件利用鼠标移动的 X 和 Y 坐标进行滚动。</p><p>现在让我们来看看 CSS 的部分，这将使我们的工作更有意义。</p><h3 id="-css--1">如何用 CSS 设计自定义光标的样式</h3><pre><code class="language-css">body{
  background-color: #1D1E22;
  cursor: none;
}

.rounded{
  width: 30px;
  height: 30px;
  border: 2px solid #fff;
  border-radius: 50%;
}

.pointed{
  width: 7px;
  height: 7px;
  background-color: white;
  border-radius: 50%;
}</code></pre><p>看一下上面的 CSS 代码，我禁用了光标（记得 <code>cursor:none</code> 吗）， 这将使光标不可见，只允许我们的自定义光标显示。</p><p>我对这些 <code>div</code> 设置了样式，使它们具有独特的“光标式”外观。你绝对可以用它做得更多，也许可以添加背景图片、表情符号、贴纸等等，只要有图片就可以了。现在，让我们看一下 JavaScript。</p><h3 id="-javascript--1">如何使用 JavaScript 来使光标移动</h3><pre><code class="language-javascript">const cursorRounded = document.querySelector('.rounded');
const cursorPointed = document.querySelector('.pointed');


const moveCursor = (e)=&gt; {
  const mouseY = e.clientY;
  const mouseX = e.clientX;
   
  cursorRounded.style.transform = `translate3d(${mouseX}px, ${mouseY}px, 0)`;
  
  cursorPointed.style.transform = `translate3d(${mouseX}px, ${mouseY}px, 0)`;
 
}

window.addEventListener('mousemove', moveCursor)</code></pre><p>我在全局窗口对象上添加了一个事件监听器来监听任何鼠标移动。当鼠标移动时，<code>moveCursor</code> 函数表达式被调用，它接收事件对象作为参数。有了这个参数，我就能在页面的任何一点上获得鼠标的 X 和 Y 坐标。</p><p>我已经使 用JavaScript <code>querySelector</code> 从 DOM 中选择了每种光标。所以我所要做的就是根据鼠标的 X 和 Y 坐标移动它们，方法是用 <code>translate3d</code> 值控制样式上的 <code>transform</code> 属性。这样，当鼠标移动到网页上的任何一点时，这些 div 就能移动。</p><p>而你所看到的反斜线被称为模板字面量。这样就可以很容易地写出变量，把它们附加到字符串中。另一种方法是将变量与字符串连接起来。</p><p>很简单，对吗？</p><p>下面是一个 CodePen 示例和上述代码片段的结果：</p><figure class="kg-card kg-embed-card kg-card-hascaption"><iframe id="cp_embed_gOGjeZG" src="https://codepen.io/developeraspire5/embed/preview/gOGjeZG?default-tabs=js%2Cresult&amp;height=300&amp;host=https%3A%2F%2Fcodepen.io&amp;slug-hash=gOGjeZG" title="Customized cursor with JavaScript" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;" loading="lazy"></iframe><figcaption>使用 JavaScript 自定义鼠标指针</figcaption></figure><h2 id="--1">哪种方法效果最好</h2><p>现在就看你作为开发者选择哪种最适合你的方法了。如果你想使用一些漂亮的表情符号或图像作为光标，你可以选择使用 CSS。另一方面，你可能想使用 JavaScript，这样你就可以根据自己的选择定制复杂的形状，并对光标的移动进行动画处理。</p><p>无论哪种方式都可以，只要你能得到你想要的结果，并打动你的网站的所有访问者。</p><p>我希望你从这篇文章中学到了很多东西，我期待着看到你用这些知识建立的网站。</p><p>想了解更多的 CSS 技巧，请在 <a href="https://twitter.com/DeveloperAspire">Twitter</a> 上关注我。</p><p>谢谢你阅读本文。</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ CSS 字体颜色——如何为 HTML 中的文本设置样式 ]]>
                </title>
                <description>
                    <![CDATA[ 在你正在创建的网站上设置文本颜色，一开始可能会让人困惑。但在这篇文章中，你会学到如何去设置。 如何在 HTML 中设置文本颜色 在 CSS 中，background-color 属性对于设置任何东西的背景色都是非常直接的。 那么，如果你想设置页面上某些东西的前景色，该怎么办？特别是文本，在正常情况下，你不会想为它设置背景色。 在 CSS 中没有前景色属性，所以使这成为可能的是 color 属性。 在这篇文章中，我将向你介绍如何使用 color 属性来设置文本的颜色。我们还将看看它取值的各种方式。 color 属性以 4 种不同的方式取值：命名颜色、十六进制颜色、RGB 颜色和 HSL 颜色。现在让我们来看看每一种方式。 命名的颜色 顾名思义，你使用了 color  属性，并通过命名你想要的颜色来应用这个值。这可能是红色、绿色、蓝色、橙色、深红色、青色，或任何其他命名的颜色。浏览器识别的命名颜色大约有 147 种。 基本的语法是这样的： element {     color: colorName } <p>freeCodeCamp</p>  p {      ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/css-font-color-how-to-style-text-in-html/</link>
                <guid isPermaLink="false">637b580a206aea0762969aa7</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Miya Liu ]]>
                </dc:creator>
                <pubDate>Fri, 18 Nov 2022 10:50:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2022/11/Cssfontcolor.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/css-font-color-how-to-style-text-in-html/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">CSS Font Color – How to Style Text in HTML</a>
      </p><p>在你正在创建的网站上设置文本颜色，一开始可能会让人困惑。但在这篇文章中，你会学到如何去设置。</p><h2 id="-html-">如何在 HTML 中设置文本颜色</h2><p>在 CSS 中，<code>background-color</code> 属性对于设置任何东西的背景色都是非常直接的。</p><p>那么，如果你想设置页面上某些东西的前景色，该怎么办？特别是文本，在正常情况下，你不会想为它设置背景色。</p><p>在 CSS 中没有前景色属性，所以使这成为可能的是 <code>color</code> 属性。</p><p>在这篇文章中，我将向你介绍如何使用 <code>color</code> 属性来设置文本的颜色。我们还将看看它取值的各种方式。</p><p><code>color</code> 属性以 4 种不同的方式取值：命名颜色、十六进制颜色、RGB 颜色和 HSL 颜色。现在让我们来看看每一种方式。</p><h2 id="-">命名的颜色</h2><p>顾名思义，你使用了 <code>color</code> 属性，并通过命名你想要的颜色来应用这个值。这可能是红色、绿色、蓝色、橙色、深红色、青色，或任何其他命名的颜色。浏览器识别的命名颜色大约有 147 种。</p><p>基本的语法是这样的：</p><pre><code class="language-css">element {
    color: colorName
}
</code></pre><pre><code class="language-html">&lt;p&gt;freeCodeCamp&lt;/p&gt;
</code></pre><pre><code class="language-css"> p {
     color: crimson;
}
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/named-color.png" class="kg-image" alt="named-color" width="600" height="400" loading="lazy"></figure><h2 id="--1">十六进制颜色（或简称十六进制颜色）</h2><p>十六进制值用于表示总共有 6 个字符的颜色。它们以磅/数字符号（#）开始，然后是 0 至 9 的任何数字，最后是 A 至 F 的任何字母。</p><p>前两个值代表红色，后两个代表绿色，而最后两个代表蓝色。使用十六进制值，你可以使用的颜色深浅没有限制。</p><pre><code class="language-html">&lt;p&gt;freeCodeCamp&lt;/p&gt;
</code></pre><pre><code class="language-css"> p {
    color: #dc143c;
 }
</code></pre><h2 id="rgb-"><strong>RGB 颜色</strong></h2><p>RGB 是红、绿、蓝的意思。使用 RGB 颜色，你可以用你想要的红色、绿色和蓝色的量来指定颜色。所有这三种颜色都用 0 到 255 之间的数字表示。</p><p>有一种类型的 RGB 叫做 <code>rgba</code>。额外的 a 代表 alpha，它让你指定颜色的不透明度。它的数值从 0.0 到 1.0——0.0 表示 0% 不透明度，0.5 表示 50% 不透明度，1.0 表示 100% 不透明度。</p><p>基本语法是 <code>rgba(amountOfRed, amountOfGreen, amountOfBlue, alpha)</code>。</p><p>如果你不想要 alpha 值，你可以把它限制为 <code>rgba(amountOfRed, amountOfGreen, amountOfBlue)</code>。</p><p>下面是常规 RGB 值的语法：</p><pre><code class="language-html">&lt;p&gt;freeCodeCamp&lt;/p&gt;
</code></pre><pre><code class="language-css"> p {
   color: rgb(220, 20, 60);
 }
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/rgb-color.png" class="kg-image" alt="rgb-color" width="600" height="400" loading="lazy"></figure><p>这是 alpha 值为 50%（0.5）的效果：</p><pre><code class="language-css">p {
    color: rgb(219, 20, 60, 0.5);
}
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/rgb-fifty-percent-opacity.png" class="kg-image" alt="rgb-fifty-percent-opacity" width="600" height="400" loading="lazy"></figure><h2 id="hsl-"><strong>HSL 颜色</strong></h2><p>HSL 是色相、饱和度和亮度的缩写。它是在 CSS 中为文本（以及其他任何需要颜色的东西）指定颜色的另一种方式。</p><ul><li>色相 Hue 代表 360° 的色轮。所以，0° 是红色，120° 是绿色，240° 是蓝色。</li><li>饱和度 Saturation 是指颜色中的灰色量，以百分比表示。0% 是灰色的阴影，100% 是颜色本身。</li><li>明度 Lightness 是指颜色中的暗度和亮度，以百分比表示。0% 是黑色，100% 是白色。</li></ul><p>就像 RGB 颜色一样，你也可以设置颜色的不透明度。所以，也有 hsla。</p><p>完整的基本语法是 <code>hsl(colorDegree, saturationPercentage, lightnessPercentage, alpha)</code>。如果你不想要 alpha 值，你可以把它限制为 <code>hsl(colorDegree, saturationPercentage, lightnessPercentage)</code>。</p><pre><code class="language-html">&lt;p&gt;freeCodeCamp&lt;/p&gt;
</code></pre><pre><code class="language-css"> p {
   color: hsl(348, 83%, 47%);
 }
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/hsl-color.png" class="kg-image" alt="hsl-color" width="600" height="400" loading="lazy"></figure><p>你可以像这样给 hsl 颜色应用一个特定的不透明度：</p><pre><code class="language-css"> p {
   color: hsla(348, 83%, 47%, 0.5);
  }
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/hsl-fifty-percent-opacity-1.png" class="kg-image" alt="hsl-fifty-percent-opacity-1" width="600" height="400" loading="lazy"></figure><h2 id="-hex-rgb-hsl-">你应该使用命名颜色、Hex 颜色、RGB 颜色还是 HSL 颜色来设置颜色？</h2><p>CSS 的奇妙之处在于，有多种方法可以做同一件事。你已经看到了这一点，在文本中应用颜色。</p><p>既然你可以用 4 种不同的方式来应用颜色，你一定想知道哪种方式是最好用的。</p><p>当你使用命名的颜色时，你在应用不同颜色的深浅方面有点受限制。红色、绿色、蓝色、黄色或任何其他命名的颜色都有很多变化，你无法使用命名的颜色。你只能使用浏览器认可的大约 147 种预定义颜色。</p><p>十六进制的颜色是非常动态的。它们是开发者中最常用的。使用十六进制颜色，你可以使用各种色调，甚至使用一种从未有人使用过的颜色。</p><p>RGB 颜色和十六进制颜色一样是动态的。除了能够指定你想要多少红色、绿色和蓝色，从 0 到 255，你还可以通过额外的 alpha 值设置你想要的颜色的透明度。</p><p>HSL 是最有活力的。你可以在色轮中从 0 到 360 度指定你想要的确切颜色，设置你想要的饱和度和暗度的百分比，还可以设置 0.0 到 1.0 的不透明度。</p><p>因此，这真的取决于你和你的使用情况——以及你想发挥多大程度的创造性。</p><h2 id="--2"><strong>总结</strong></h2><p>对文本应用颜色有助于使你的网站对访问者更有吸引力。正确的颜色组合也可以帮助你的内容变得更具有可读性。</p><p>在这篇文章中，你已经学会了如何用颜色属性的 4 种不同的值来给文本应用颜色。</p><p>谢谢你阅读本文，继续编码吧。</p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
