<?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[ reset0 - 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[ reset0 - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/chinese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 26 May 2026 20:24:15 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/chinese/news/author/reset0/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ 交互式设计——如何评估交互成本并改善用户体验 ]]>
                </title>
                <description>
                    <![CDATA[ 有三个核心技能是每个现代产品设计师必须掌握的：产品思维、视觉设计和交互设计。 所有现代产品设计师的基本素养 一般来说，你应该在这三个方面都很擅长，但你应该真正擅长其中两个方面。大多数设计师可以通过在线资源、实践和交付真实产品来自学视觉设计和产品思维。 作为一家 FAANG 公司的产品设计负责人，我已经指导了数百名有抱负的设计师，我发现交互设计往往是设计师自学的最具有挑战性的核心技能。 在本文中，我提供了一个学习和提高交互设计技能的基础和框架。 UX（用户体验）和 IxD（交互设计）之间的区别什么是交互成本？ 交互设计背后的基础概念是“交互成本”，它经常被用来衡量一个产品的可用性。Nielsen Norman 将“交互成本”定义为用户为达到其目标而必须付出的 精神和体力的总和 [https://www.nngroup.com/articles/interaction-cost-definition/]。 一般来说，我们希望尽可能降低交互成本。但是，这很困难。因为随着你的产品覆盖的用例越多，这将变得困难。 支持更多的用例和功能会增加产品信息架构（IA）和导航的复杂度。一个用例是 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/interaction-design-evaluate-interaction-costs-improve-ux/</link>
                <guid isPermaLink="false">6391b3cb0bd1810766a86b63</guid>
                
                    <category>
                        <![CDATA[ 设计 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ reset0 ]]>
                </dc:creator>
                <pubDate>Thu, 08 Dec 2022 05:52:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2022/12/1_WzkvMd3sZRb6BCwKEsoHjA.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/interaction-design-evaluate-interaction-costs-improve-ux/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Interaction Design – How to Evaluate Interaction Costs and Improve User Experience</a>
      </p><!--kg-card-begin: markdown--><p>有三个核心技能是每个现代产品设计师必须掌握的：产品思维、视觉设计和交互设计。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2021/02/image-146.png" alt="所有现代产品设计师的基本素养" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>所有现代产品设计师的基本素养</figcaption>
</figure>
<p>一般来说，你应该在这三个方面都很擅长，但你应该真正擅长其中两个方面。大多数设计师可以通过在线资源、实践和交付真实产品来自学视觉设计和产品思维。</p>
<p>作为一家 FAANG 公司的产品设计负责人，我已经指导了数百名有抱负的设计师，我发现交互设计往往是设计师自学的最具有挑战性的核心技能。</p>
<p>在本文中，我提供了一个学习和提高交互设计技能的基础和框架。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2021/02/image-148.png" alt="UX（用户体验）和 IxD（交互设计）之间的区别" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>UX（用户体验）和 IxD（交互设计）之间的区别</figcaption>
</figure>
<h2 id="">什么是交互成本？</h2>
<p>交互设计背后的基础概念是“交互成本”，它经常被用来衡量一个产品的可用性。Nielsen Norman 将“交互成本”定义为用户为达到其目标而必须付出的<a href="https://www.nngroup.com/articles/interaction-cost-definition/">精神和体力的总和</a>。</p>
<p>一般来说，我们希望尽可能降低交互成本。但是，这很困难。因为随着你的产品覆盖的用例越多，这将变得困难。</p>
<p>支持更多的用例和功能会增加产品信息架构（IA）和导航的复杂度。一个用例是一连串的步骤，从用户的目标开始，到实现目标后的结果。</p>
<p>更复杂的 IA 本质上会增加完成用户目标所需的点击次数。例如 iOS 时钟应用具有以下闹钟用例目标：开启或关闭闹钟，创建一个新的闹钟和编辑闹钟。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2021/02/image-149.png" alt="IA 越是复杂，用户需要点击的东西就越多，才能到达他们想要的界面" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>IA 越是复杂，用户需要点击的东西就越多，才能到达他们想要的界面，鸣谢：Topta</figcaption>
</figure>
<p>经验法则的重点是减少目标用户的主要用例的交互成本。每当一个产品容纳了太多的用例（例如，有一百万个下拉菜单和功能的企业产品），它就变得更难使用。</p>
<p>为了避免这种过度复杂化，在建立一个全新的产品时，应该选择一个特定的用户和用例来关注。</p>
<h3 id="">物理和心理的交互成本</h3>
<p>许多初级设计师都有一种误区，认为交互成本等于用户完成一项任务所需的点击次数。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/02/image-150.png" alt="一个PIC和MIC的图表" width="600" height="400" loading="lazy"></p>
<p>然而，它比这更要更深入。交互成本分为心理交互成本（MIC）和物理交互成本（PIC），我将在下面解释。</p>
<h2 id="">如何评估交互成本 - 首先找到关键的用户流程</h2>
<p>最佳实践是确定主要用例（即核心任务），并在必要时以牺牲二级和三级用例为代价降低其交互成本。</p>
<p>你可以使用<a href="https://medium.muz.li/red-routes-critical-design-paths-that-make-or-break-your-app-a642ebe0940a">核心任务分析（RRA）</a>评估哪些用例交互流对你对主要用户最重要。</p>
<p>核心任务往往很重要，包括多个步骤的端对端任务、经常使用、为大量使用而构建、提供最大价值，具有明确的成功标准，并与产品指标挂钩。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2021/02/image-151.png" alt="如果产品已经上线，你可以根据用户访谈或数据来创建一个 RRA" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>如果产品已经上线，你可以根据用户访谈或数据来创建一个 RRA</figcaption>
</figure>
<p>比如说，在 Uber 应用中，乘客的关键路线是叫车，而他们的正常路线是添加支付方式。</p>
<h2 id="">特斯勒定律怎么帮助你降低交互成本</h2>
<p>根据<a href="https://lawsofux.com/laws/teslers-law/">特斯勒定律</a>的复杂性守恒定律，所有系统都具有无法消除或隐藏的内在复杂性。</p>
<p>好的设计可以确保尽可能多的复杂性负担在系统上，而不是在用户身上。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/02/image-152.png" alt="一个说明特斯勒定律的图表，其中的复杂性负担在用户与产品之间转移。" width="600" height="400" loading="lazy"></p>
<p>你应该首先减低主要用例中的交互成本，并将复杂性负担转移到最不重要的用例上。</p>
<p>Tesler 认为，设计师和工程师应该多花一周时间来降低应用的复杂度，而不是让数百万用户多花一分钟时间。</p>
<p>但是，请注意不要将接口简化到抽象的地步。常见的陷阱是牺牲 MIC 为代价来减少 PIC（就是你，苹果）。</p>
<p>当系统已经尽可能多地处理了固有的复杂性，你应该将其余的复杂性从主要用例转移到第二和第三用例。</p>
<p>大多数的数字产品都有复杂的设置，原因就在于此。在大多数情况下，设置通常是第三级用例，很少使用。</p>
<p>想象一下，如果你总是看到设置屏幕而不是主屏幕，并且需要点击几下才能到达你需要的屏幕。你可能会对这种不合理的交互成本感到沮丧。</p>
<h2 id="mic">心理交互成本（MIC）</h2>
<p><a href="https://www.researchgate.net/publication/23456170_A_Framework_of_Interaction_Costs_in_Information_Visualization">心理交互成本（MICs）</a>经常被新的设计师而忽略，他们只关注物理交互成本（PIC）。</p>
<p>你可能已经注意到，在可用性差的产品中，常见的 MIC 包括复杂的导航、密集的指示、非常规的心智模型和交互模式等。</p>
<h3 id="">注意力和记忆力</h3>
<p>MIC 的两个最重要的组成部分是注意力和记忆力。</p>
<p>当一个任务需要过多的注意力或记忆力完成时，它的 MIC 就会成比例地高 - 降低了可用性。</p>
<p>一些增长注意力成本或转移注意力的常见元素包括弹出式横幅、模型、吸引注意力的视觉效果，以及用户当前任务无关的动作。</p>
<p>用户是容易分心的，确保在他们试图完成一项任务时，你不会把他们的注意力分散到其他地方。</p>
<h3 id="">评估注意力</h3>
<p>如果你想要评估你的界面有多少注意力，可以考虑做一个<a href="https://uxplanet.org/uxers-quick-guide-to-eye-tracking-edf70bffd03d">眼动追踪研究（ETS）</a>。你不仅可以用 ETS 来推断用户观察的地方，还有推断他们在想些什么。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2021/02/image-153.png" alt="ETS 的一个例子" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>ETS 的一个例子</figcaption>
</figure>
<p>ETS 特别研究了两个相关的眼球运动：“注视”和“扫视”。</p>
<p>当用户的瞳孔在界面元素上停留足够长的时间以处理它，就会发生注视。当眼睛处于运动状态——在界面中的不同区域之间游走时，就会发生扫视。</p>
<p>如果你的 ETS 显示许多与任务无关的扫视移动，这可能是由于一个分散注意力的界面。你的 ETS 结果能帮助你了解用户是否遗漏了界面中的关键元素，哪些是分散注意力的，哪些是不必要的。</p>
<h3 id="">工作记忆</h3>
<p>所有不同类型的记忆，都有一个广泛的分类。</p>
<p>对于设计师而言，工作记忆（短期记忆的一部分）是最相关的。最短的记忆类型被称为工作类型，这在一个任务中通常只持续几秒钟的时间。</p>
<p>换句话说，我们的工作记忆负责在我们参与其他认知过程时，我们可以在脑海中保存信息。</p>
<p><a href="https://lawsofux.com/laws/millers-law/">米勒定律</a> 指出，一般人在工作记忆中一次只能保留 5-11 个项目。在你的产品中完成一项任务所需的工作记忆与你强加给用户的 MIC 负担成正比。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/02/image-154.png" alt="米勒定律的海报插图" width="600" height="400" loading="lazy"></p>
<p>反过来说，在任何时候，你的任务都不应该要求用户在工作记忆中保留七个以上的项目。</p>
<p>在极少数情况下，如果你要求用户在他们的记忆中持有超过 11 个项目，可以使用“分块”来减少他们的心理负担。分块是指将一个信息集的单个片段分解，然后归纳为一个有意义的整体。</p>
<p>例如，我们记住电话号码是 XXX-XXXX，而不是 XXXXXX。把数字分成两块，而不是一系列的七个独立单位，这样更容易记住。</p>
<p>另一个需要考虑的因素是注意力和记忆相关的是<a href="https://lawsofux.com/laws/hicks-law/">特斯勒定律</a>。该定律指出，随着决策的时间随着选择的数量和复杂性增加。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2021/02/image-155.png" alt="选择越多，用户做出决策的时间就越长" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>选择越多，用户做出决策的时间就越长</figcaption>
</figure>
<p>避免过多的选择压倒用户，尽可能突出最适合他们的选项。将复杂的任务分解成较小的步骤，也就是在适当的时候使用渐进式披露。</p>
<h2 id="pic">物理交互成本（PIC）</h2>
<p>我不会详细介绍 PIC，因为多数的设计师都非常了解它们。</p>
<p>常见的 PIC 因素包含到达距离和目标宽度（<a href="https://lawsofux.com/laws/fittss-law/">费茨法则</a>），完成一项任务所需要的用户输入和操作的数量等等。</p>
<p><a href="https://lawsofux.com/laws/fittss-law/">费茨法则</a>指出，击中目标（即点击按钮）的时间是与你的输入设备的距离和目标的击中框宽度的函数</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2021/02/image-156.png" alt="费茨法则的图示" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>费茨法则的图示</figcaption>
</figure>
<p>例如，如果你的鼠标光标离得很远，而按钮又很小，那么点击桌面上的一个按钮就需要更长的时间。</p>
<p>评估 PIC 的一个很好的方法就是<a href="https://www.nngroup.com/articles/task-analysis/">任务分析</a>和检查<a href="https://usabilitygeek.com/usability-metrics-a-guide-to-quantify-system-usability/">可用性指标</a>，如“任务时间（TT）”。</p>
<p>TT 的根源是查看完成用户目标所需要的任务数量、频率、物理要求以及任务时间。</p>
<p>TT 和可用性指标是进阶话题，完全可以另起篇章，所以我把它留到下次再讲。</p>
<h2 id="">避免常见的陷阱</h2>
<p>根据 Nielsen Norman Group 的调查，产品中最常见的导致交互成本增加的一些方面包括以下内容：</p>
<ul>
<li>过度的阅读和滚动</li>
<li>四处寻找相关信息的用户</li>
<li>理解呈现给用户的信息</li>
<li>用户的物理输入</li>
<li>页面加载和等待时间</li>
<li>注意力切换</li>
<li>记忆负荷</li>
</ul>
<h3 id="">情景交互成本</h3>
<p>根据用户的不同，上述陷阱可能或多或少是严重的。例如，有阅读障碍的用户认为阅读比普通用户更有挑战性（建议：使用对阅读障碍者友好的字体，如 <a href="https://www.dyslexiefont.com/en/typeface/">Dyslexie</a>）。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/02/image-157.png" alt="Dyslexie字体的3D动画" width="600" height="400" loading="lazy"></p>
<p><a href="https://www.dyslexiefont.com/">来源</a></p>
<p>有运动障碍的用户可能会发现点击比阅读难得多，甚至用户的设备也可能发挥重要作用。例如，如果手机的网速很慢，在移动设备上加载页面可能需要很长时间。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/02/image-158.png" alt="一个标准的加载旋钮" width="600" height="400" loading="lazy"></p>
<h3 id="">交互路径与动机</h3>
<p>在某些情况下，用户可以采取多种可能的路径来完成他们的目标。用户根据“预期效用”的概念来决定采取哪条路径，其定义为：预期效用 = 预期收益 - 预期互动成本。</p>
<p>换句话说，用户会权衡每个动作的收益和成本，并选择收益与成本最平衡的路径。</p>
<p>用户会倾向于具有最低预期交互成本的路径。即使有一个成本较低的路径，如果这个路径不直观或不熟悉，他们最终会选择他们更熟悉的路径，因为 MIC 较低。</p>
<p>具有高动机的用户（例如，由于你的营销或品牌推广）更有可能为完成他们的目标付出高昂的互动成本。 例如，如果苹果公司的网站有很高的交互成本，但用户可能仍然有足够的动力来完成他们的任务。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/02/image-159.png" alt="image-159" width="600" height="400" loading="lazy"></p>
<p>苹果是世界上最有价值的品牌是有原因的。</p>
<p>但是，如果用户想购买一个普通产品，并且结账过程有很高的交互成本，他们就会改从竞争对手那里购买。</p>
<p>有关更多详细信息，请查看 Nielsen Norman Group 的<a href="https://www.nngroup.com/articles/interaction-cost-definition/">如何评估用例的交互成本的示例</a>，找出“仪式”一词的来源。</p>
<h2 id="">总结</h2>
<p>了解交互成本是任何现代产品设计师的一项重要技能。我们鼓励你超越表面的交互设计考虑，深入研究众多的 PIC 和 MIC 因素。</p>
<p>当然，我们应该努力尽可能地减少交互成本。但在必不得已的情况下，我们应该做出权衡，以确保主要用例的摩擦最小。</p>
<p>一个很好的第一步是建立一个准则、框架和测试的心理模型，以评估你的设计的交互成本。</p>
<p>如果你喜欢这篇文章，<a href="https://theambitiousdesigner.substack.com/">加入我的免费订阅邮件</a>“雄心勃勃的设计师”，以获得更多职业和设计方面的见解。</p>
<p>我还在 Facebook 上运营一个<a href="https://www.facebook.com/groups/richarduxmentorship">私人指导小组</a>和一个设计 <a href="https://www.instagram.com/richard.ux/">Instagram</a> 账户。</p>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 从零开始使用 HTML、CSS 和 JavaScript 搭建 PWA ]]>
                </title>
                <description>
                    <![CDATA[ 原文：How to build a PWA from scratch with HTML, CSS, and JavaScript [https://www.freecodecamp.org/news/build-a-pwa-from-scratch-with-html-css-and-javascript/] ，作者：Ibrahima Ndaw [https://www.freecodecamp.org/news/author/ibrahima92/] 渐进式 Web 应用是一种能给传统 Web 应用带来原生应用体验的方式。使用 PWA ，我们能够使用移动应用的特性来增强我们的网站，从而提高网站的可用性，并提供良好的用户体验。 在这篇文章中，我们将使用 HTML、CSS 和 JavaScript 从零开始构建 PWA。我们要讨论的主题有：  * 什么是渐进式 Web App ?  * 标记  * 样式  * 用 JavaScript 显示数据  * Web 应用 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/build-a-pwa-from-scratch-with-html-css-and-javascript/</link>
                <guid isPermaLink="false">603cc75dc354c605689eaad4</guid>
                
                    <category>
                        <![CDATA[ PWA渐进式Web应用 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ reset0 ]]>
                </dc:creator>
                <pubDate>Wed, 13 Apr 2022 02:50:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/03/Group-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>原文：<a href="https://www.freecodecamp.org/news/build-a-pwa-from-scratch-with-html-css-and-javascript/">How to build a PWA from scratch with HTML, CSS, and JavaScript</a>，作者：<a href="https://www.freecodecamp.org/news/author/ibrahima92/">Ibrahima Ndaw</a></p><!--kg-card-begin: markdown--><p>渐进式 Web 应用是一种能给传统 Web 应用带来原生应用体验的方式。使用 PWA ，我们能够使用移动应用的特性来增强我们的网站，从而提高网站的可用性，并提供良好的用户体验。</p>
<p>在这篇文章中，我们将使用 HTML、CSS 和 JavaScript 从零开始构建 PWA。我们要讨论的主题有：</p>
<ul>
<li>什么是渐进式 Web App ?</li>
<li>标记</li>
<li>样式</li>
<li>用 JavaScript 显示数据</li>
<li>Web 应用 Manifest</li>
<li>什么是 Service Worker?</li>
<li>缓存资源</li>
<li>获取资源</li>
<li>注册 Service Worker</li>
<li>最后的想法</li>
<li>更多资源</li>
</ul>
<p>那么，让我们从一个重要的问题开始：PWA 到底是什么？</p>
<h2 id="webapp">什么是渐进式 Web App ?</h2>
<p>渐进式 Web 应用是一种通过使用现代 Web 能力向用户提供类似于应用程序的体验的 Web 应用程序。总而言之，它只是一个运行在浏览器上且使用了一些增强特性的普通网站。它赋予你以下的能力：</p>
<ul>
<li>安装到你的手机桌面上</li>
<li>离线访问</li>
<li>使用摄像头</li>
<li>通知推送</li>
<li>后台同步</li>
</ul>
<p>等等。</p>
<p>但是，为了将传统的 Web 应用转换成 PWA，我们必须对其做出一些小调整，添加一个 manifest 文件和 service worker。</p>
<p>别担心这些新术语，我们将会在下面介绍它们。</p>
<p>首先，我们必须要构建传统的 Web 应用，所以让我们从编写结构开始吧。</p>
<h2 id="">标记</h2>
<p>这个 HTML 文件十分简单，我们只需要将所有内容放置在 <code>main</code> 标签内即可</p>
<ul>
<li>在 <code>index.html</code></li>
</ul>
<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;meta http-equiv="X-UA-Compatible" content="ie=edge" /&gt;
        &lt;link rel="stylesheet" href="css/style.css" /&gt;
        &lt;title&gt;Dev'Coffee PWA&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;main&gt;
            &lt;nav&gt;
                &lt;h1&gt;Dev'Coffee&lt;/h1&gt;
                &lt;ul&gt;
                    &lt;li&gt;Home&lt;/li&gt;
                    &lt;li&gt;About&lt;/li&gt;
                    &lt;li&gt;Blog&lt;/li&gt;
                &lt;/ul&gt;
            &lt;/nav&gt;
            &lt;div class="container"&gt;&lt;/div&gt;
        &lt;/main&gt;
        &lt;script src="js/app.js"&gt;&lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>然后用 <code>nav</code> 标签来创建一个导航栏。用 <code>div</code> 标签来创建一个 class 为 <code>container</code> 的元素来放置剩下的卡片，稍后我们将使用 Javascript 来添加它们。</p>
<p>现在我们把这些都弄好了，让我们用 CSS 来给它加点样式。</p>
<h2 id="">样式</h2>
<p>向往常一样，我们需要先引入一些字体。然后我们再重置某些默认样式。</p>
<ul>
<li>在 <code>css/style.css</code></li>
</ul>
<pre><code class="language-css">@import url('https://fonts.googleapis.com/css?family=Nunito:400,700&amp;display=swap');
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}
body {
    background: #fdfdfd;
    font-family: 'Nunito', sans-serif;
    font-size: 1rem;
}
main {
    max-width: 900px;
    margin: auto;
    padding: 0.5rem;
    text-align: center;
}
nav {
    display: flex;
    justify-content: space-between;
    align-items: center;
}
ul {
    list-style: none;
    display: flex;
}
</code></pre>
<p>然后我们限制 <code>main</code> 元素的最大宽度为 <code>900px</code>让它在大屏幕上看起来有更好的呈现方式。</p>
<p>对于导航栏 ，我希望 logo 在左边，链接在右边。所以对于 <code>nav</code> 标签，将其设为 flex 容器后，我们使用 <code>justify-content: space-between;</code> 将其对齐。</p>
<ul>
<li>在 <code>css/style.css</code></li>
</ul>
<pre><code class="language-css">.container {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    grid-gap: 1rem;
    justify-content: center;
    align-items: center;
    margin: auto;
    padding: 1rem 0;
}
.card {
    display: flex;
    align-items: center;
    flex-direction: column;
    width: 15rem auto;
    height: 15rem;
    background: #fff;
    box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
    border-radius: 10px;
    margin: auto;
    overflow: hidden;
}
.card--avatar {
    width: 100%;
    height: 10rem;
    object-fit: cover;
}
.card--title {
    color: #222;
    font-weight: 700;
    text-transform: capitalize;
    font-size: 1.1rem;
    margin-top: 0.5rem;
}
.card--link {
    text-decoration: none;
    background: #db4938;
    color: #fff;
    padding: 0.3rem 1rem;
    border-radius: 20px;
}
</code></pre>
<p>我们有几个卡片，所以 container 元素将使用 grid 布局来显示。然后添加属性 <code>grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr))</code>，我们现在能够使卡片具有响应式。这样的话如果有足够空间它们将最少具有 <code>15rem</code> 的宽度（如果没有则足够的空间则使用 <code>1fr</code>）。</p>
<p>然后为了使它们更加好看，我们在 <code>.card</code> 类上添加了双倍的阴影效果，并在 <code>.card--avatar</code> 上使用 <code>object-fit: cover</code> 属性为了防止图像的拉伸</p>
<p>现在它看起来更好看了，但是我们仍然没有数据显示。</p>
<p>让我们在下一节来解决这个问题。</p>
<h2 id="javascript">使用 JavaScript 显示数据</h2>
<p>请注意，我使用了较大的图片，加载它会需要一些时间。这将以最好的方式向你展示 service workers 的能力。</p>
<p>正如我之前说过用 Class 名为 <code>.container</code> 的元素保存我们的卡片，因此我们需要选择它。</p>
<ul>
<li>在 <code>js/app.js</code></li>
</ul>
<pre><code class="language-javascript">const container = document.querySelector('.container');
const coffees = [
    { name: 'Perspiciatis', image: 'images/coffee1.jpg' },
    { name: 'Voluptatem', image: 'images/coffee2.jpg' },
    { name: 'Explicabo', image: 'images/coffee3.jpg' },
    { name: 'Rchitecto', image: 'images/coffee4.jpg' },
    { name: ' Beatae', image: 'images/coffee5.jpg' },
    { name: ' Vitae', image: 'images/coffee6.jpg' },
    { name: 'Inventore', image: 'images/coffee7.jpg' },
    { name: 'Veritatis', image: 'images/coffee8.jpg' },
    { name: 'Accusantium', image: 'images/coffee9.jpg' },
];
</code></pre>
<p>然后，我们创建一个包含名字和图片的卡片数组。</p>
<ul>
<li>在 <code>js/app.js</code></li>
</ul>
<pre><code class="language-javascript">const showCoffees = () =&gt; {
  let output = ""
  coffees.forEach(
    ({ name, image }) =&gt;
      (output += `
              &lt;div class="card"&gt;
                &lt;img class="card--avatar" src=${image} /&gt;
                &lt;h1 class="card--title"&gt;${name}&lt;/h1&gt;
                &lt;a class="card--link" href="#"&gt;Taste&lt;/a&gt;
              &lt;/div&gt;
              `)
  )
  container.innerHTML = output
}

document.addEventListener("DOMContentLoaded", showCoffees)

</code></pre>
<p>有了上面的代码，我们现在能够通过遍历数组并将其显示在 HTML 上。为了保证工作正常，我们等待 DOM （文档对象模型）内容加载完成再执行 <code>showCoffees</code> 方法。</p>
<p>我们已经做了很多了，但现在我们只有一个传统的 Web 应用。所以，让我们在下一节通过引入一些 PWA 的特性来改变这种情况。</p>
<p><img src="https://media.giphy.com/media/l3V0dy1zzyjbYTQQM/source.gif" alt="super-excited" width="600" height="400" loading="lazy"></p>
<h2 id="webmanifest">Web 应用 Manifest</h2>
<p>web 应用 manifest 是一个简单的 JSON 文件，它向浏览器告知你的 web 应用。它告诉浏览器在移动设备或桌面安装时该如何表现。而要显示”添加到主屏幕“的提示，则需要 web 应用 manifest。</p>
<p>现在我们知道 web manifest 是什么了，让我们在根目录创建一个名为 <code>manifest.json</code> 的新文件（你得这样命名）。然后在里面添加这些代码。</p>
<ul>
<li>在 <code>manifest.json</code></li>
</ul>
<pre><code class="language-javascript">{
  "name": "Dev'Coffee",
  "short_name": "DevCoffee",
  "start_url": "index.html",
  "display": "standalone",
  "background_color": "#fdfdfd",
  "theme_color": "#db4938",
  "orientation": "portrait-primary",
  "icons": [
    {
      "src": "/images/icons/icon-72x72.png",
      "type": "image/png", "sizes": "72x72"
    },
    {
      "src": "/images/icons/icon-96x96.png",
      "type": "image/png", "sizes": "96x96"
    },
    {
      "src": "/images/icons/icon-128x128.png",
      "type": "image/png","sizes": "128x128"
    },
    {
      "src": "/images/icons/icon-144x144.png",
      "type": "image/png", "sizes": "144x144"
    },
    {
      "src": "/images/icons/icon-152x152.png",
      "type": "image/png", "sizes": "152x152"
    },
    {
      "src": "/images/icons/icon-192x192.png",
      "type": "image/png", "sizes": "192x192"
    },
    {
      "src": "/images/icons/icon-384x384.png",
      "type": "image/png", "sizes": "384x384"
    },
    {
      "src": "/images/icons/icon-512x512.png",
      "type": "image/png", "sizes": "512x512"
    }
  ]
}

</code></pre>
<p>最后，这个 JSON 文件具有一些可填和必填的属性。</p>
<p>name: 当浏览器显示启动画面时，在屏幕上显示的名称。</p>
<p>short_name: 你的 app 在主屏幕上显示的快捷方式的名称。</p>
<p>start_url: 当你的 app 打开时，所要显示的页面。</p>
<p>display: 告诉浏览器如何显示你的 app。有几种模式可以选择，如<code>minimal-ui</code>、<code>fullscreen</code>、<code>browser</code>等等。这里我们使用<code>standalone</code>模式来隐藏与浏览器有关的任何内容。</p>
<p>background_color: 当浏览器显示启动画面时，指定屏幕的背景颜色。</p>
<p>theme_color: 当我们打开 app 的时候指定状态栏的背景颜色。</p>
<p>orientation: 告诉浏览器显示 app 时的方向。</p>
<p>icons： 当浏览器显示启动画面时，在屏幕上显示的图标。我们在这里使用了所有尺寸以及任何设备的首选图标，但是你只能选择一到两个，由你决定。</p>
<p>现在我们有了一个 web 应用的 manifest，让我们来将它添加到 html 文件中。</p>
<ul>
<li>在 <code>index.html</code> (head 标签中)</li>
</ul>
<pre><code class="language-html">&lt;link rel="manifest" href="manifest.json" /&gt;
&lt;!-- ios support --&gt;
&lt;link rel="apple-touch-icon" href="images/icons/icon-72x72.png" /&gt;
&lt;link rel="apple-touch-icon" href="images/icons/icon-96x96.png" /&gt;
&lt;link rel="apple-touch-icon" href="images/icons/icon-128x128.png" /&gt;
&lt;link rel="apple-touch-icon" href="images/icons/icon-144x144.png" /&gt;
&lt;link rel="apple-touch-icon" href="images/icons/icon-152x152.png" /&gt;
&lt;link rel="apple-touch-icon" href="images/icons/icon-192x192.png" /&gt;
&lt;link rel="apple-touch-icon" href="images/icons/icon-384x384.png" /&gt;
&lt;link rel="apple-touch-icon" href="images/icons/icon-512x512.png" /&gt;
&lt;meta name="apple-mobile-web-app-status-bar" content="#db4938" /&gt;
&lt;meta name="theme-color" content="#db4938" /&gt;
</code></pre>
<p>如你所看到的，我们在 head 标签里引入了<code>manifest.json</code>文件。并且还引入了一些其他文件来处理 IOS 上的图标显示、状态栏颜色和主题色。</p>
<p>现在我们可以深入探讨最后一步并介绍 service worker。</p>
<h2 id="serviceworker">什么是 Service Worker?</h2>
<p>需要注意的是，由于 service worker 能够访问并处理请求，所以 PWA 仅在 https 上运行。因此安全是必须的。</p>
<p>service worker 是浏览器在后台的独立线程中运行的脚本。这意味着它将在不同的地方运行，并且与你的页面完全隔离，这就是为什么它不能操纵你的 DOM 元素的原因。</p>
<p>不过，它的功能超级强大。service worker 能拦截并处理网络请求，管理缓存以实现离线访问或者向你的用户推送通知。</p>
<p><img src="https://media.giphy.com/media/5VKbvrjxpVJCM/source.gif" alt="wow" width="600" height="400" loading="lazy"></p>
<p>所以让我们在根目录下创建第一个 service worker，并命名为<code>serviceWorker.js</code>(名称由你决定)。但是你必须将它放在根目录上，这样你就不会把它的范围限制在一个文件夹里。</p>
<h3 id="">资源缓存</h3>
<ul>
<li>在 <code>serviceWorker.js</code></li>
</ul>
<pre><code class="language-javascript">const staticDevCoffee = 'dev-coffee-site-v1';
const assets = [
    '/',
    '/index.html',
    '/css/style.css',
    '/js/app.js',
    '/images/coffee1.jpg',
    '/images/coffee2.jpg',
    '/images/coffee3.jpg',
    '/images/coffee4.jpg',
    '/images/coffee5.jpg',
    '/images/coffee6.jpg',
    '/images/coffee7.jpg',
    '/images/coffee8.jpg',
    '/images/coffee9.jpg',
];
</code></pre>
<p>这段代码看起来有点吓人，但它只是 JavaScript 而已（所以别担心）。</p>
<p>我们声明了缓存的名称<code>staticDevCoffee</code>和要储存在缓存中的资源。为了执行这些操作，我们需要给<code>self</code>添加一个监听器。</p>
<p><code>self</code>就是 service worker 本身。它能够让我们监听生命周期中的事件并做一些对应的事情。</p>
<p>service worker 有几个生命周期，其中之一是 <code>install</code> 事件。当 service worker 被安装时，它就会运行。它在 worker 执行后立即触发，而且每个 service worker 只调用一次。</p>
<p>当<code>install</code>事件触发时，回调函数将被调用，通过这个回调函数我们可以访问<code>event</code>对象。</p>
<p>在浏览器上缓存某些内容的时候可能需要一些时间才能完成，因为它是异步的。</p>
<p>为了处理这个问题，我们需要使用<code>waitUntil()</code>。正如你所猜的这样，它会等待操作完成。</p>
<p>一旦 cache API 准备就绪，我们可以执行<code>open()</code>方法，并通过将缓存名称当作参数传递给<code>caches.open(staticDevCoffee)</code>来创建我们的缓存。</p>
<p>它会返回一个 promise，将帮助我们使用<code>cache.addAll(assets)</code>将我们的资源储存在缓存中。</p>
<p><img src="https://drive.google.com/uc?id=1ynBQRQ00wHo5J6CnjfLCX3b3UNiSrGqZ" alt="image-cache" width="600" height="400" loading="lazy"></p>
<p>希望你能理解这些内容。</p>
<p><img src="https://media.giphy.com/media/OQEcw90jACeU8/source.gif" alt="desesperate" width="600" height="400" loading="lazy"></p>
<p>现在，我们已经顺利的把资源缓存到浏览器中。而下次我们加载页面时，如果我们处于离线状态， service worker 将会处理该请求并获取缓存。</p>
<p>所以，让我们取回我们的缓存吧。</p>
<h3 id="">获取资源</h3>
<ul>
<li>在 <code>serviceWorker.js</code></li>
</ul>
<pre><code class="language-javascript">self.addEventListener('fetch', (fetchEvent) =&gt; {
    fetchEvent.respondWith(
        caches.match(fetchEvent.request).then((res) =&gt; {
            return res || fetch(fetchEvent.request);
        })
    );
});
</code></pre>
<p>Here, we use the <code>fetch</code> event to, well, get back our data. The callback gives us access to <code>fetchEvent</code>. Then we attach <code>respondWith()</code> to prevent the browser's default response. Instead it returns a promise because the fetch action can take time to finish.</p>
<p>这里，我们使用<code>fetch</code>事件来获取我们的数据，通过回调函数我们可以访问<code>fetchEvent</code>。我们添加<code>respondWith()</code> 来阻止浏览器的默认响应。然后返回一个 promise，因为 fetch 操作可能需要一些时间才能完成。</p>
<p>当一个缓存准备就绪时，我们将使用 <code>caches.match(fetchEvent.request)</code>。它将检查缓存中是否有与<code>fetchEvent.request</code>匹配的内容。顺便一提，<code>fetchEvent.request</code>只是我们的 assets 数组。</p>
<p>然后，它会返回一个 promise。如果缓存存在，我们可以直接返回它，否则则返回最初的 fetch。</p>
<p>现在， 我们的资源可以被 service worker 缓存并获取，这将大大的优化了我们的图片的加载时间。</p>
<p>最重要的是，它使我们的应用可以在离线模式下使用。</p>
<p>但现在 service worker 还不能工作，我们还需要在我们的项目中注册它。</p>
<p><img src="https://media.giphy.com/media/Z9EvIRmLEOS3JNFeVb/source.gif" alt="let-s-do-it" width="600" height="400" loading="lazy"></p>
<h2 id="serviceworker">注册 Service Worker</h2>
<ul>
<li>在 <code>js/app.js</code></li>
</ul>
<pre><code class="language-javascript">if ('serviceWorker' in navigator) {
    window.addEventListener('load', function () {
        navigator.serviceWorker
            .register('/serviceWorker.js')
            .then((res) =&gt; console.log('service worker registered'))
            .catch((err) =&gt; console.log('service worker not registered', err));
    });
}
</code></pre>
<p>在这里，我们先检查当前浏览器是否支持<code>serviceWorker</code>（因为并未所有的浏览器都支持它）。</p>
<p>然后，我们将监听页面的 load 事件来注册我们的 service worker。通过传递文件名<code>serviceWorker.js</code>作为参数给<code>navigator.serviceWorker.register()</code>来作为注册 service worker 的参数。</p>
<p>通过上述步骤，我们现在已经将传统的 web 应用转换成为 PWA。</p>
<p><img src="https://media.giphy.com/media/3o6ZtlGkjeschymLNm/source.gif" alt="we-did-it" width="600" height="400" loading="lazy"></p>
<h2 id="">最后的想法</h2>
<p>在本文中，我们已经看到了 PWA 的神奇之处。通过添加一个 web 应用 manifest 和一个 service worker，确实提高了我们传统 web 应用的用户体验。这是因为 PWA 快速、安全、可靠，更重要的是它支持离线模式。</p>
<p>现在很多的框架都已经为我们设置了好了 service worker 文件。但是知道如何用 Vanilla JavaScript 来实现它可以帮你理解 PWA。</p>
<p>而且你还可通过动态缓存资源或者限制缓存大小等方法更进一步的使用 service worker。</p>
<p>感谢你阅读本文。</p>
<p>你可以在线上<a href="https://devcoffee-pwa.netlify.com/">浏览</a>，源代码在<a href="https://github.com/ibrahima92/pwa-with-vanilla-js">这里</a>。</p>
<p>在我的博客上阅读我的更多文章。</p>
<h2 id="">更多资源</h2>
<p><a href="https://developers.google.com/web/fundamentals/web-app-manifest">Web Manifest 文档</a></p>
<p><a href="https://developers.google.com/web/fundamentals/primers/service-workers">Service Worker 文档</a></p>
<p><a href="https://app-manifest.firebaseapp.com/">Web Manifest 生成器</a></p>
<p><a href="https://caniuse.com/#search=service%20worker">浏览器支持</a></p>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 如何使用 CSS 选择器设计网页样式 ]]>
                </title>
                <description>
                    <![CDATA[ CSS选择器是是CSS最重要的部分之一。它们使你能够在网页上针对你想要的HTML元素设置样式。 如果没有CSS选择器，你就无法将页面设置成你想要的样子。 值得庆幸的是，CSS选择器已经存在一段时间了，你可以随心所欲地对你的元素进行样式设计。 但如果你真的想要释放CSS的力量并创建令人惊叹的元素，那么你需要了解你能用CSS选择器做什么。也就是说，你需要先了解基本的CSS选择器，然后再学习高级的CSS选择器。 这篇文章将对这两方面进行研究。到最后，你会发现，你已经开始释放CSS选择器的力量并创造自己的不可思议的元素。所以，让我们从什么是CSS选择器开始吧。 什么是CSS选择器？ 如果你之前写过任何CSS，那么你可能已经见过CSS选择器了。它们是CSS规则的第一部分，你可以使用CSS选择器来选择你要设置样式的HTML元素。 在CSS里，选择器由CSS选择器规范来定义。这意味着某个选择器必须是相应的浏览器支持 [https://www.w3.org/TR/selectors-3/#selectors]的，这个选择器才能运行。 CSS选择器通常分为五个不同的种类。这篇文章将从基础和 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/use-css-selectors-to-style-webpage/</link>
                <guid isPermaLink="false">60eaff51e9280e0667df2c8b</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ reset0 ]]>
                </dc:creator>
                <pubDate>Sat, 10 Jul 2021 11:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/07/john-mark-arnold-ti4kGLkGgmU-unsplash-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>CSS选择器是是CSS最重要的部分之一。它们使你能够在网页上针对你想要的HTML元素设置样式。</p>
<p>如果没有CSS选择器，你就无法将页面设置成你想要的样子。</p>
<p>值得庆幸的是，CSS选择器已经存在一段时间了，你可以随心所欲地对你的元素进行样式设计。</p>
<p>但如果你真的想要释放CSS的力量并创建令人惊叹的元素，那么你需要了解你能用CSS选择器做什么。也就是说，你需要先了解基本的CSS选择器，然后再学习高级的CSS选择器。</p>
<p>这篇文章将对这两方面进行研究。到最后，你会发现，你已经开始释放CSS选择器的力量并创造自己的不可思议的元素。所以，让我们从什么是CSS选择器开始吧。</p>
<h2 id="css">什么是CSS选择器？</h2>
<p>如果你之前写过任何CSS，那么你可能已经见过CSS选择器了。它们是CSS规则的第一部分，你可以使用CSS选择器来选择你要设置样式的HTML元素。</p>
<p>在CSS里，选择器由CSS选择器规范来定义。这意味着某个选择器必须是相应的浏览器<a href="https://www.w3.org/TR/selectors-3/#selectors">支持</a>的，这个选择器才能运行。</p>
<p>CSS选择器通常分为五个不同的种类。这篇文章将从基础和高级两个关键类别来研究它们。以下是这五个类别。</p>
<ol>
<li>简单选择器</li>
<li>组合选择器</li>
<li>伪类选择器</li>
<li>伪元素选择器</li>
<li>属性选择器</li>
</ol>
<p>想要做好一件事，你必须了解基础知识，所以让我们从这里开始。</p>
<h1 id="">基础选择器</h1>
<p>你可能见过许多类型的选择器 - 这些基本的CSS选择器足以让你构建时尚的网页。让我们来看看每个基本的CSS选择器，以确保我们了解它们的作用。</p>
<h2 id="css">CSS 元素（标签）选择器</h2>
<p>CSS元素选择器根据元素名来选择HTML元素。在HTML中，元素名就是类似于<code>h1</code>、 <code>p</code>的东西，或者类似于<code>article</code>或<code>footer</code>之类有意义的名字。因此，元素选择器选择所有具有你指定的名称的HTML元素。</p>
<p>让我们来看看元素选择器的例子吧：</p>
<pre><code class="language-css">/* selecting all h3 elements */
h3 {
 text-align: center;
 color: blue;
}

/* selecting all article elements */
article {
 font-size: 14px;
 line-height: 1.1px;
}
</code></pre>
<p>在以上的例子，我们选择器页面上标签名为<code>h3</code>和<code>article</code>的所有元素，并对这些元素应用了样式。</p>
<p>元素选择器帮助你保持代码的简洁，并将样式应用页面上这种类型的所有元素上。</p>
<h2 id="cssid">CSS ID 选择器</h2>
<p>ID选择器选择具有匹配的ID属性的HTML元素。由于在一个HTML文档中不能有一个以上具有相同ID的元素，这个选择器允许你选择一个单独的元素。这意味着所选元素将是唯一的。</p>
<p>要选择一个具有特定ID的元素，你可以使用<code>#</code>（哈希）字符，后面跟着是HTML元素的ID。在这种情况下它看起来就像这样<code>#id-name</code>。</p>
<p>让我们来看看ID选择器的例子吧。</p>
<pre><code class="language-css">#projects-flex-container {
 width: 90vw;
 display: flex;
}
</code></pre>
<p>在上面这个例子里，我们选择了ID为<code>#projects-flex-container</code>的单个元素，并对其应用了样式。这个样式只适用于那些单独的元素。</p>
<p>不过，有一点需要注意的是，在使用ID选择器时，你应该小心。由于ID选择器不能在其他元素上重复使用，你应该问你自己是否需要使用ID选择器来选择该元素。</p>
<h2 id="css">CSS 类选择器</h2>
<p>类选择器选择具有相同的class属性的HTML元素。类选择器对于定位多个元素很有用，比如你想要匹配样式的卡片或图像。</p>
<p>要选择具有特定类别的元素，你可以使用一个<code>.</code>字符（句号），然后在它后面加上类别的名称。</p>
<p>让我们来看看CSS类选择器的例子。</p>
<pre><code class="language-css">.project-card {
 color: #badA55;
 padding: 5px;
 border-radius: 5px;
}
</code></pre>
<p>上述的例子中，我们使用CSS类选择器选择了类名为<code>project-card</code>的所有元素。所有具有<code>project-card</code>类的元素将被应用列出的样式。</p>
<h2 id="">通用选择器</h2>
<p>通用选择器用来选择所有的HTML元素，这意味者你页面上的每一个元素，从标题到页脚。你会经常使用它来页面的边距和填充保持一致，或者重置样式。</p>
<p>通用选择器的语法是<code>*</code>字符（星号）。</p>
<pre><code class="language-css">* {
 margin: 0;
 padding: 0;
}
</code></pre>
<p>上述的例子中，通过使用通用选择器，它将整个页面的margin和padding清零。</p>
<h1 id="css">什么是CSS分組选择器</h1>
<p>在我们讨论高级CSS选择器之前，我们需要快速了解一下分組选择器。这是一种常见的做法，你会在外面经常看到，它有助于使你的代码干净和可读。</p>
<p>分组允许你一次选择多个HTML元素，并且只声明一次它们的样式。</p>
<p>让我们来看看组合选择器的例子吧。</p>
<pre><code class="language-css">h1 {
 text-align: left;
 letter-spacing: 3px;
 color: #111111;
}

h2 {
 text-align: left;
 letter-spacing: 3px;
 color: #111111;
}

h3 {
 text-align: left;
 letter-spacing: 3px;
 color: #111111;
}
</code></pre>
<p>上面的CSS代码中，我们有三个元素<code>h1</code>、<code>h2</code>和<code>h3</code>，这三个元素都有相同的样式定义。因此，我们可以通过选择器分组来清理我们的代码。</p>
<p>为了给选择器分组，我们用<code>,</code>字符（逗号）将每个选择器分开。</p>
<pre><code class="language-css">h1, h2, h3 {
 text-align: left;
 letter-spacing: 3px;
 color: #111111;
}
</code></pre>
<p>因为它们的样式是一样的，我们现在只需要写一次。</p>
<p>请注意，分組选择器可用于本文中所提及的所有选择器，也就是说，选择器不一定是要和上述代码一样的，也可以是其他的。</p>
<p>如果我们想让它们共享样式定义，我们可以把一个类选择器和一个ID选择器分组。而我们可以把匹配的样式属性和值分组，然后在每个元素上设置不同的定义。</p>
<p>让我们拓展我们的例子来理解这个概念。</p>
<pre><code class="language-css">/*group the selectors and state definitions that are the same*/

h1, h2, h3 {
 text-align: left;
 letter-spacing: 3px;
 color: #111111;
}

/*apply individual styles to selectors*/

h1 {
 font-size: 72px;
}

h2 {
 font-size: 48px;
}

h3 {
 font-size: 32px;
}
</code></pre>
<p>这就是所有的基本选择器，如果你想学好CSS，你需要了解每个选择器的作用。有了这些知识，你现在应该可以做到这一点了。</p>
<p>如果你想提高你的CSS水平，那么你将要了解高级的CSS选择器。</p>
<h1 id="css">高级CSS选择器</h1>
<p>高级CSS选择器允许你突破CSS的界限，它们可以高度具体地确定你要选择哪些元素，以及选择该元素时它处于什么状态。</p>
<p>让我们直接进入一些高级选择器，看看属性选择器。</p>
<h2 id="css">CSS属性选择器</h2>
<p>属性选择器允许你根据某个属性是否存在来选择元素。换句话来说，这个CSS选择器将匹配页面上的任何元素，如果它有某个属性的话。</p>
<p>属性是添加到HTML元素开始标签中的内容，它可以是<code>id</code>、<code>name</code>或<code>value</code>等内容。</p>
<pre><code class="language-HTML">&lt;a title="Learn to code for free!" href="https://www.freecodecamp.org/"&gt;Learn to code&lt;/a&gt;
</code></pre>
<p>title是a元素中的一个属性。</p>
<p>有七个属性选择器，它们分别允许你根据一个属性是否存在以及值可能包含的内容来查找元素。</p>
<ol>
<li>当前选择器</li>
<li>等于选择器（<code>=</code>）</li>
<li>以指定值开头选择器（<code>^</code>）</li>
<li>以指定值结尾选择器（<code>$</code>）</li>
<li>包含选择器（<code>*</code>）</li>
<li>空白选择器（<code>~</code>）</li>
<li>连字符选择器（<code>|</code>）</li>
</ol>
<p>这些选择器的通用语法是选择器后跟<code>[]</code>（方括号），你可以在里面说明要查找的内容。选择器可以是类选择器，甚至是通用选择器。</p>
<pre><code class="language-css">selector[attribute] 
</code></pre>
<p>今天我们将看看五个最常用的属性选择器，为了了解这五个属性选择器，让我们用例子来看看它们中的每一个。</p>
<h3 id="">当前属性选择器</h3>
<p>这个属性选择器根据元素是否存在该属性来查找任何元素。</p>
<p>让我们来看看当前属性选择器的例子吧。</p>
<pre><code class="language-css">a[title] {
 color: khaki;
 background: grey; 
}
</code></pre>
<p>在上述的例子中，我们的当前属性选择器查找了任何包含<code>title</code>属性的<code>a</code>元素，并对它们应用样式。其他所有没有包含title属性的a元素则不会应用这些样式。</p>
<h3 id="">等于属性选择器</h3>
<p>这个属性选择器可以找到一个完全匹配属性值的元素。要使用这个选择器，你要在属性名后跟一个<code>=</code>（等号）来寻找完全匹配的值。</p>
<p>让我们来看看等于选择器的例子吧。</p>
<pre><code class="language-css">a[href="&lt;https://peterlunch.com/&gt;"] {
 color: purple;
} 
</code></pre>
<p>在上述的例子中，等于选择器选择了所有<code>a</code>元素中有<code>href</code>属性且值为 "<a href="https://peterlunch.com/">https://peterlunch.com/</a>" 的元素。</p>
<h3 id="">以指定值开头选择器</h3>
<p>这个属性选择器查找指定属性中以你指定的值开头的元素。要使用这个选择器，请先说明你要查找的属性，紧接着跟一个 <code>^</code> 和 <code>=</code> 符号，然后是你要匹配的值。</p>
<p>让我们来看看以指定值开头选择器的例子吧。</p>
<pre><code class="language-css">a[href^="https"] {
 color: yellow;
 text-decoration: none;
}
</code></pre>
<p>上述这个例子中，以指定值开头选择器查找了任何有<code>href</code>属性且值为“https”开头的<code>a</code>元素。</p>
<h3 id="">以指定值结尾的属性选择器</h3>
<p>与以指定值开头选择器非常相似，这个属性选择器正好相反，它可以找到任何已你指定的值结束的元素。</p>
<p>要使用这个属性选择器，请先说明你要查找的属性，紧接着一个 <code>$</code> 和 <code>=</code> 符号，然后是你要匹配的值。</p>
<p>让我们来看看以指定值结束选择器的例子吧。</p>
<pre><code class="language-css">img[src$="/blog-imgs"] {
 border-radius: 4px;
 box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}
</code></pre>
<p>在上述的例子中，以指定值结束选择器查找了任何有<code>src</code>属性且以"/blog-imgs"结束的<code>img</code>元素。这是我实际用于我的网站中的一个。</p>
<h3 id="">包含属性选择器</h3>
<p>这个属性选择器查找任何属性值某处包含你要找的值的元素。这意味着该值至少包含一个出现的值。</p>
<p>要使用这个选择器，请先说明你要查找的元素，紧接着一个 <code>*</code> 和 <code>=</code> 符号，然后是你要找的一个出现的值。</p>
<p>让我们来看看包含属性选择器的例子吧。</p>
<pre><code class="language-css">a[href*="peterlunch"] {
 color: green;
}
</code></pre>
<p>在上述的例子中，包含属性选择器查找了任意<code>href</code>属性中包含"peterlunch"的值的<code>a</code>元素。</p>
<p>属性选择器就到此为止，让我们进入下一个高级选择器。</p>
<h2 id="">组合选择器</h2>
<p>下一个高级选择器是组合选择器。这个选择器可以结合一个或以上的CSS选择器。在CSS中，有四种类型的组合选择器。</p>
<ol>
<li>后代选择器</li>
<li>直接子代选择器</li>
<li>相邻兄弟选择器</li>
<li>通用兄弟选择器</li>
</ol>
<p>要理解这些选择器如何工作，你必须首先理解HTML遵循一个家族树的层级结构。这意味着有一个父元素，它可以包含子元素，而子元素可以有子元素。以此类推，就像一颗家庭树。</p>
<pre><code class="language-html">&lt;div&gt; &lt;!--parent--&gt;
 &lt;p&gt; &lt;!--div child--&gt;
 &lt;article&gt; &lt;!--div child, parent to h1 &amp; p--&gt;  
  &lt;h1&gt;
   &lt;p&gt;&lt;/p&gt;
  &lt;/h1&gt;
 &lt;/article&gt;
 &lt;article&gt; 
  &lt;h1&gt;
   &lt;p&gt;&lt;/p&gt;
   &lt;p&gt;&lt;/p&gt;
  &lt;/h1&gt;
 &lt;/article&gt;
&lt;/div&gt;
</code></pre>
<p>在上述的例子中，<code>div</code>是父元素，它的子元素是<code>article</code>，而<code>article</code>是<code>h1</code>和<code>p</code>子元素的父元素。</p>
<p>有了这些知识铺垫，让我们通过实践逐一探讨这些组合选择器，以了解它们的工作原理。</p>
<h3 id="">后代选择器</h3>
<p>后代选择器匹配所有指定元素的后代的所有元素</p>
<p>让我们来看看后代选择器的例子吧。</p>
<pre><code class="language-css">div p {
 line-height: 2em;
}
</code></pre>
<p>上述的例子中选择了<code>div</code>元素里的所有<code>p</code>元素。</p>
<h3 id="">直接后代选择器</h3>
<p>直接后代选择器匹配指定的元素的后代的所有元素。这与后代选择器不同，因为它只选择副元素的直接子元素。</p>
<p>子选择器用<code>&gt;</code>字符来表示。</p>
<p>让我们来看看直接后代选择器的例子吧。</p>
<pre><code class="language-css">div &gt; p {
 color: aquamarine;
}
</code></pre>
<p>参照上面的HTML层级结构的例子，这个选择器将将只找到第一个<code>p</code>标签，而不是<code>article</code>标签中的<code>p</code>标签，因为它们不是父元素<code>div</code>的直接子元素。</p>
<h3 id="">相邻兄弟选择器</h3>
<p>相邻兄弟选择器用<code>+</code>来表示，它将两个选择器分开，只有在第二个选择器元素紧跟随第一个元素时才与之匹配。</p>
<p>一个很好的现实例子是，将紧跟在图片后面的文本设置为标题样式。</p>
<pre><code class="language-css">img + p {
 font-size: 10px;
 color: grey;
 font-style: italic;
}
</code></pre>
<p>在上述的例子中，<code>img</code>元素后面的任何<code>p</code>元素都将使用上述定义来进行样式处理。</p>
<h3 id="">通用兄弟选择器</h3>
<p>通用兄弟选择器选择某一元素的任意兄弟元素，通用兄弟选择器使用<code>~</code>字符来表示。</p>
<p>让我们来看看通用兄弟选择器的例子吧。</p>
<pre><code class="language-css">article ~ h1 {
 font-weight: 900;
}
</code></pre>
<p>在上述例子中，它选择了所有<code>h1</code>元素，这些元素是<code>article</code>元素的同级别的。</p>
<h3 id="">伪选择器</h3>
<p>伪选择器可分为两类。第一个是<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes">伪类选择器</a>，第二个是<a href="https://peterlunch.com/css-pseudo-elements/">伪元素选择器</a>。</p>
<p>这些选择器很复杂，有很多选项。为了理解它们，值得单独阅读一些关于它们的文章，因为它们本身就是复杂的主题。但是，我在这里简要的介绍一下两者。</p>
<p>首先，伪类选择器根据某种状态选择元素。你可能已经见过<code>:hover</code>或<code>:active</code>这样的东西，这些是页面上的元素的状态。你可以根据该元素是否处于指定的状态来选择元素。</p>
<p>一个简单的例子是：</p>
<pre><code class="language-css">button:hover {
 background: red;
}
</code></pre>
<p>在上述的例子中，当用户在一个按钮上悬停时，背景颜色将会变为红色。</p>
<p>如果你想要更好的理解伪类选择器，我推荐你阅读Nash Vail的<a href="https://chinese.freecodecamp.org/news/explained-css-pseudo-classes-cef3c3177361/">这篇文章</a>，他对伪类的解释非常好。</p>
<p>接下来是我在<a href="https://peterlunch.com/css-pseudo-elements/">这篇文章</a>中写过的伪元素选择器。这些选择器选择元素中的一部分，一个元素中的一部分可能是元素的第一个字母或者是该元素前后的内容。</p>
<p>对于伪类选择器，值得注意的是它们像伪类一样使用 <code>::</code>（双冒号）与<code>:</code>单冒号。</p>
<pre><code class="language-CSS">p {
  width: 600px;
  line-height: 1.5;
  font-weight: 500;
}

p::first-letter {
  color: white;
  background-color: rgb(55, 97, 117);
  border-radius: 3px;
  box-shadow: 3px 3px 0 rgb(212, 173, 81);
  font-size: 250%;
  padding: 6px 3px;
  margin-right: 6px;
  float: left;
}
</code></pre>
<h2 id="">总结</h2>
<p>现在你应该对CSS选择器有了很好的理解，以及如何使用它们来查找网页上的HTML元素。</p>
<p>希望你喜欢阅读这篇文章。如果你在这篇文章中学到了什么，那么请查看我的<a href="https://bit.ly/2Re6Vdf">其他文章</a>或订阅<a href="https://mailchi.mp/bfaa8a288d7c/7o1pve3bv9">我的频道</a>以获得非常好的新手教程。</p>
<!--kg-card-end: markdown--><p>原文：<a href="https://www.freecodecamp.org/news/use-css-selectors-to-style-webpage/">How to Use CSS Selectors to Style Your Web Page</a>，作者：<a href="https://www.freecodecamp.org/news/author/peter-lynch/">Peter Lynch</a></p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
