相关文章推荐

这是第一个完全使用 CSS 网格 的 GUI 挑战赛演示!下面是使用 Chrome 开发者工具(适用于网格) 突出显示的每个网格:

仅用于填充空白

最常见的布局:

foo {
  display: grid;
  gap: var(--something);

我将此布局称为“仅用于间距”,因为它仅使用网格在各个块之间添加间距。

有 5 种布局采用了此策略,下面显示了它们的所有内容:

包含每个输入组 (.fieldset-item) 的 fieldset 元素使用 gap: 1px 在元素之间创建细线边框。无需复杂的边框解决方案!

填充的空白
.grid {
  display: grid;
  gap: 1px;
  background: var(--bg-surface-1);
  & > .fieldset-item {
    background: var(--bg-surface-2);

居中显示封装内容

Flexbox 和网格都为 align-itemsalign-content 提供了功能,在处理换行元素时,content 布局对齐方式会将空间作为一个组分配给子元素。

main {
  display: grid;
  gap: var(--space-xl);
  place-content: center;

主元素使用 place-content: center 对齐方式简写,以便在单列和双列布局中将子元素垂直和水平居中。

请观看上方视频,了解“content”如何保持居中,即使发生了换行也是如此。

重复自动调整最小/最大值

<form> 为每个部分使用自适应网格布局。此布局会根据可用空间从一列切换为两列。

form {
  display: grid;
  gap: var(--space-xl) var(--space-xxl);
  grid-template-columns: repeat(auto-fit, minmax(min(10ch, 100%), 35ch));
  align-items: flex-start;
  max-width: 89vw;

此网格在 row-gap (--space-xl) 和 column-gap (--space-xxl) 中的值不同,以便在响应式布局中添加自定义风格。当列堆叠时,我们希望有较大的间距,但不应像在大屏幕上那样大。

grid-template-columns 属性使用 3 个 CSS 函数:repeat()minmax()min()Una Kravets 有一篇出色的布局博文,其中将其称为 RAM

与 Una 的布局相比,我们的布局中增加了 3 项特殊内容:

  • 我们传递一个额外的 min() 函数。
  • 我们指定 align-items: flex-start
  • 有一个 max-width: 89vw 样式。
  • Evan Minto 在其博客上的 Intrinsically Responsive CSS Grid with minmax() and min() 一文中对额外的 min() 函数进行了详细说明。建议您阅读该文档。flex-start 对齐校正旨在移除默认的拉伸效果,以便此布局的子项无需具有相同的高度,而是可以具有自然的固有高度。您可以观看 YouTube 视频,快速了解这项新功能。

    本文将对 max-width: 89vw 进行简要介绍。我来展示一下应用和未应用样式的布局:

    发生了什么?指定 max-width 时,它会为 auto-fit 布局算法提供上下文、显式大小或确定大小,以便其知道可在空间中容纳多少个重复项。虽然该空间似乎显然是“全宽”,但根据 CSS 网格规范,必须提供明确的尺寸或最大尺寸。我已提供最大尺寸。

    为什么选择 89vw?因为它对我的布局“有效”。 我和其他几位 Chrome 团队成员正在调查为什么更合理的值(例如 100vw)不够用,以及这是否确实是一个 bug。

    此布局的和谐感主要来自于有限的间距调色板(确切来说是 7 种)。

    :root {
      --space-xxs: .25rem;
      --space-xs:  .5rem;
      --space-sm:  1rem;
      --space-md:  1.5rem;
      --space-lg:  2rem;
      --space-xl:  3rem;
      --space-xxl: 6rem;
    

    这些流程非常适合与网格、CSS @nest@media 的级别 5 语法搭配使用。下面是一个示例,即完全 <main> 布局样式集。

    main {
      display: grid;
      gap: var(--space-xl);
      place-content: center;
      padding: var(--space-sm);
      @media (width >= 540px) {
          padding: var(--space-lg);
      @media (width >= 800px) {
          padding: var(--space-xl);
    

    内容居中显示的网格,默认情况下内边距适中(如移动设备上)。但是,随着可用的视口空间增多,它会通过增加内边距而展开。2021 年 CSS 看起来不错!

    还记得之前的布局“just for gap”吗?下面是这些元素在此组件中的更完整的外观:

    header {
      display: grid;
      gap: var(--space-xxs);
    section {
      display: grid;
      gap: var(--space-md);
    

    通过控制颜色的使用,此设计既富有表现力又极简,从而脱颖而出。我是这样做的:

    :root {
      --surface1: lch(10 0 0);
      --surface2: lch(15 0 0);
      --surface3
    
    
    
    
        
    : lch(20 0 0);
      --surface4: lch(25 0 0);
      --text1: lch(95 0 0);
      --text2: lch(75 0 0);
    
    

    我使用数字来命名 Surface 和文本颜色,而不是使用 surface-darksurface-darker 等名称,因为在媒体查询中,我会翻转这些颜色,而“浅色”和“深色”没有意义。

    我在偏好媒体查询中进行切换,如下所示:

    :root {
      @media (prefers-color-scheme: light) {
          --surface1: lch(90 0 0);
          --surface2: lch(100 0 0);
          --surface3: lch(98 0 0);
          --surface4: lch(85 0 0);
          --text1: lch(20 0 0);
          --text2: lch(40 0 0);
    
    

    在深入了解颜色语法细节之前,请务必先快速了解整体情况和策略。不过,我说得有点超前了,让我先回过头来。

    不必深入研究颜色理论,LCH 是一种以人为本的语法,它适应我们感知颜色的方式,而不是我们用数学(例如 255)衡量颜色的方式。这使其具有明显的优势,因为人类可以更轻松地编写它,其他人也能适应这些调整。

    今天,在本演示中,我们将重点关注我用于切换亮色和深色模式的语法和值。我们来看看 1 个 Surface 和 1 种文本颜色:

    :root {
      --surface1: lch(10 0 0);
      --text1:    lch(95 0 0);
      @media (prefers-color-scheme: light) {
          --surface1: lch(90 0 0);
          --text1:    lch(40 0 0);
    

    --surface1: lch(10 0 0) 表示亮度为 10%、色度为 0 且色相为 0:一种非常深的无色灰色。然后,在浅色模式的媒体查询中,使用 --surface1: lch(90 0 0); 将浅色值翻转为 90%。这就是该策略的要点。首先,只需在 2 个主题之间更改亮度,同时保持设计要求的对比度或可保持无障碍功能的对比度即可。

    lch() 的优势在于,轻盈感是面向用户的,我们可以放心地对其进行 % 更改,因为在感知上,它会始终保持 % 不同。例如,hsl() 不太可靠

    如果您有兴趣,可以详细了解色彩空间和 lch()。即将推出!

    CSS 目前根本无法访问这些颜色。 我再重复一遍:我们无法再在大多数现代显示器上看到三分之一的颜色。这些并不是普通的颜色,而是屏幕可以显示的最鲜艳的颜色。由于显示器硬件的演变速度快于 CSS 规范和浏览器实现,因此我们的网站看起来很模糊。

    Lea Verou

    采用配色方案的自适应表单控件

    许多浏览器都提供深色主题控件(目前包括 Safari 和 Chromium),但您必须在 CSS 或 HTML 中指定您的设计使用这些控件。

    以上示例展示了通过 DevTools 的“样式”面板应用该属性的效果。演示版使用 HTML 代码,我认为这种位置通常更好:

    <meta name="color-scheme" content="dark light">
    

    如需详细了解,请参阅 Thomas Steiner 撰写的这篇 color-scheme 文章。除了深色复选框输入之外,您还可以获得更多好处!

    CSS accent-color

    表单元素的 accent-color近期出现了一些活动,它是一种 CSS 样式,可以更改浏览器输入元素中使用的着色颜色。如需详细了解,请点击此处前往 GitHub。我已将其添加到此组件的样式中。由于浏览器支持它,我的复选框将更加符合主题,并采用粉色和紫色醒目配色。

    input[type="checkbox"] {
      accent-color: var(--brand);
    

    使用固定渐变和焦点内效果突出显示颜色

    颜色在使用得当时最能吸引眼球,我喜欢通过色彩丰富的界面互动来实现这一点。

    上方视频中包含多层界面反馈和互动,这些反馈和互动通过以下方式为互动增添了个性:

  • 突出显示上下文。
  • 提供有关值在范围内的“饱满程度”的界面反馈。
  • 提供界面反馈,指明字段正在接受输入。
  • 为了在用户与元素互动时提供反馈,CSS 使用 :focus-within 伪类来更改各种元素的外观,我们来拆解一下 .fieldset-item,它非常有趣:

    .fieldset-item {
      &:focus-within {
        background: var(--surface2);
        & svg {
          fill: white;
        & picture {
          clip-path: circle(50%);
          background: var(--brand-bg-gradient) fixed;
    

    当此元素的某个子元素获得焦点时:

  • .fieldset-item 背景分配了对比度更高的 Surface 颜色。
  • 嵌套的 svg 填充为白色,以提高对比度。
  • 嵌套的 <picture> clip-path 会扩展为一个完整的圆形,背景会填充明亮的固定渐变。
  • 自定义范围

    下面是一个 HTML 输入元素,我将向您展示如何自定义其外观:

    <input type="range">
    

    我们需要自定义此元素的 3 个部分:

  • 范围元素 / 容器
  • 范围元素样式

    input[type="range"] {
      /* style setting variables */
      --track-height: .5ex;
      --track-fill: 0%;
      --thumb-size: 3ex;
      --thumb-offset: -1.25ex;
      --thumb-highlight-size: 0px;
      appearance: none;         /* clear styles, make way for mine */
      display: block;
      inline-size: 100%;        /* fill container */
    
    
    
    
        
    
      margin: 1ex 0;            /* ensure thumb isn't colliding with sibling content */
      background: transparent;  /* bg is in the track */
      outline-offset: 5px;      /* focus styles have space */
    

    CSS 的前几行是样式的自定义部分,希望明确标记它们有所帮助。其余样式大多是重置样式,旨在为构建组件的棘手部分提供一致的基础。

    input[type="range"]::-webkit-slider-runnable-track {
      appearance: none; /* clear styles, make way for mine */
      block-size: var(--track-height);
      border-radius: 5ex;
      background:
        /* hard stop gradient:
            - half transparent (where colorful fill we be)
            - half dark track fill
            - 1st background image is on top
        linear-gradient(
          to right,
          transparent var(--track-fill),
          var(--surface1) 0%
        /* colorful fill effect, behind track surface fill */
        var(--brand-bg-gradient) fixed;
    

    诀窍在于“揭示”鲜艳的填充颜色。这项操作是通过顶部的硬停止渐变实现的。在填充百分比之前,渐变是透明的,之后使用未填充的轨道 Surface 颜色。未填充的 Surface 后面是全宽颜色,等待透明度显示出来。

    轨道填充样式

    我的设计确实需要 JavaScript 才能保持填充样式。虽然有仅使用 CSS 的策略,但它们要求滑块元素的高度与滑道相同,而我无法在这些限制范围内找到合适的解决方案。

    /* grab sliders on page */
    const sliders = document.querySelectorAll('input[type="range"]')
    /* take a slider element, return a percentage string for use in CSS */
    const rangeToPercent = slider => {
      const max = slider.getAttribute('max') || 10;
      const percent = slider.value / max * 100;
      return `${parseInt(percent)}%`;
    /* on page load, set the fill amount */
    sliders.forEach(slider => {
      slider.style.setProperty('--track-fill', rangeToPercent(slider));
      /* when a slider changes, update the fill prop */
      slider.addEventListener('input', e => {
        e.target.style.setProperty('--track-fill', rangeToPercent(e.target));
    

    我认为这会带来不错的视觉效果升级。滑块在没有 JavaScript 的情况下也能正常运行,--track-fill 属性不是必需的,如果不存在,它只会没有填充样式。如果 JavaScript 可用,请填充自定义属性,同时观察任何用户更改,并将自定义属性与值同步。

    Ana TudorCSS-Tricks 上撰写了一篇精彩的文章,演示了一种仅使用 CSS 的轨道填充解决方案。我还发现此 range 元素非常有启发性。

    input[type="range"]::-webkit-slider-thumb {
      appearance: none; /* clear styles, make way for mine */
      cursor: ew-resize; /* cursor style to support drag direction */
      border: 3px solid var(--surface3);
      block-size: var(--thumb-size);
      inline-size: var(--thumb-size);
      margin-top: var(--thumb-offset);
      border-radius: 50%;
      background: var(--brand-bg-gradient) fixed;
    

    其中大多数样式都是用于绘制圆形。您再次看到了固定的背景渐变,它统一了滑块、滑道和关联的 SVG 元素的动态颜色。我将互动样式分离开来,以便隔离用于悬停突出显示的 box-shadow 技术:

    @custom-media --motionOK (prefers-reduced-motion: no-preference);
    ::-webkit-slider-thumb {
      /* shadow spread is initally 0 */
      box-shadow: 0 0 0 var(--thumb-highlight-size) var(--thumb-highlight-color);
      /* if motion is OK, transition the box-shadow change */
      @media (--motionOK) {
          transition: box-shadow .1s ease;
      /* on hover/active state of parent, increase size prop */
      @nest input[type="range"]:is(:hover,:active) & {
    
    
    
    
        
    
        --thumb-highlight-size: 10px;
    
    

    我们的目标是打造一个易于管理且带有动画效果的视觉亮点,以便用户提供反馈。通过使用阴影,我可以避免使用此效果触发布局。为此,我创建了一个未模糊处理且与滑块元素的圆形相匹配的阴影。然后,我更改了悬停时的展开大小并进行了过渡。

    要是复选框的突出显示效果也能如此轻松地实现就好了…

    跨浏览器选择器

    我发现,为了实现跨浏览器一致性,我需要使用以下 -webkit--moz- 选择器:

    input[type="range"] {
      &::-webkit-slider-runnable-track {}
      &::-moz-range-track {}
      &::-webkit-slider-thumb {}
      &::-moz-range-thumb {}
    
    

    自定义复选框

    下面是一个 HTML 输入元素,我将向您展示如何自定义其外观:

    <input type="checkbox">
    

    我们需要自定义此元素的 3 个部分:

  • 复选框元素
  • 关联的标签
  • 突出显示效果
  • 复选框元素

    input[type="checkbox"] {
      inline-size: var(--space-sm);   /* increase width */
      block-size: var(--space-sm);    /* increase height */
      outline-offset: 5px;            /* focus style enhancement */
      accent-color: var(--brand);     /* tint the input */
      position: relative;             /* prepare for an absolute pseudo element */
      transform-style: preserve-3d;   /* create a 3d z-space stacking context */
      margin: 0;
      cursor: pointer;
    

    transform-styleposition 样式为我们稍后介绍的用于设置精彩集锦样式的伪元素做准备。除此之外,我提出的大部分建议都是一些个人风格方面的小建议。我希望将光标设为指针,我喜欢轮廓偏移,默认复选框太小,如果支持 accent-color,请将这些复选框纳入品牌配色方案。

    复选框标签

    为复选框提供标签非常重要,原因有 2 点:第一个用于表示复选框值的用途,以回答“开启或关闭什么?”这个问题。其次,从用户体验的角度来看,网页用户已经习惯通过关联的标签与复选框进行互动。

    <label for="text-notifications">
      <h3>Text Messages</h3>
      <small>Get notified about all text messages sent to your device</small>
    </label>

    在标签上,添加一个 for 属性,指向 ID 为 <label for="text-notifications"> 的复选框。在复选框中,请为名称和 ID 添加相同的值,以确保用户可以使用各种工具和技术(例如鼠标或屏幕阅读器)找到该复选框:<input type="checkbox" id="text-notifications" name="text-notifications">。建立关联后,您可以免费使用 :hover:active 等功能,从而增加与表单互动的方式。

    复选框突出显示

    我想保持界面的一致性,并且滑块元素有一个不错的缩略图突出显示效果,我想将其与复选框搭配使用。缩略图能够使用 box-shadow 及其 spread 属性来放大和缩小阴影。不过,这种效果在这里不起作用,因为我们的复选框是方形的,并且应该是方形的。

    我使用伪元素和大量棘手的 CSS 实现了相同的视觉效果:

    @custom-media --motionOK (prefers-reduced-motion: no-preference);
    input[type="checkbox"]::before {
      --thumb-scale: .01;                        /* initial scale of highlight */
      --thumb-highlight-size: var(--space-xl);
      content: "";
      inline-size: var(--thumb-highlight-size);
      block-size: var(--thumb-highlight-size);
      clip-path: circle(50%);                     /* circle shape */
      position: absolute;                         /* this is why position relative on parent */
      top: 50%;                                   /* pop and plop technique (https://web.dev/centering-in-css#5-pop-and-plop) */
      left: 50%;
      background: var(--thumb-highlight-color);
      transform-origin: center center;            /* goal is a centered scaling circle */
      transform:                                  /* order here matters!! */
        translateX(-50%)                          /* counter balances left: 50% */
        translateY(-50%)                          /* counter balances top: 50% */
        translateZ(-1px)                          /* PUTS IT BEHIND THE CHECKBOX */
        scale(var(--thumb-scale))                 /* value we toggle for animation */
      will-change: transform;
      @media (--motionOK) {                       /* transition only if motion is OK */
          transition: transform .2s ease;
    /* on hover, set scale custom property to "in" state */
    input[type="checkbox"]:hover::before {
      --thumb-scale: 1;
    

    创建圆形伪元素是一件简单的工作,但将其放置在所附加元素后面却比较困难。下面是问题解决前后的对比图:

    这绝对是一个微互动,但对我来说,保持视觉一致性非常重要。动画缩放技术与我们在其他地方使用的方法相同。我们将自定义属性设为新值,并让 CSS 根据动作偏好设置对其进行转换。其中的关键功能是 translateZ(-1px)。父元素创建了一个 3D 空间,而此伪元素子元素通过将自己稍微向后放置在 z 空间中来访问该空间。

    该 YouTube 视频非常详细地演示了此设置组件的鼠标、键盘和屏幕阅读器互动。我会在这里介绍一些详细信息。

    HTML 元素选项

    <header> <fieldset> <picture> <label> <input>

    其中每个元素都包含有关用户浏览工具的提示。有些元素提供互动提示,有些元素用于关联互动,有些元素有助于构建屏幕阅读器导航的无障碍功能树。

    HTML 属性

    我们可以隐藏屏幕阅读器不需要的元素,在本例中,就是滑块旁边的图标:

    <picture aria-hidden="true">
    

    上方视频演示了 Mac OS 上的屏幕阅读器流程。请注意输入焦点如何直接从一个滑块移至下一个滑块。这是因为我们隐藏了可能在前往下一个滑块的途中作为停止点的图标。如果没有此属性,用户就需要停止、聆听并跳过他们可能看不到的图片。

    SVG 包含一系列数学运算,我们来添加一个 <title> 元素,用于显示鼠标悬停时显示的标题,以及一个可供人阅读的注释,说明数学运算的用途:

    <svg viewBox="0 0 24 24">
      <title>A note icon</title>
      <path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/>
    

    除此之外,我们使用了足够多的明确标记的 HTML,因此该表单在鼠标、键盘、视频游戏控制器和屏幕阅读器上均能顺利测试。

    JavaScript

    已经介绍过如何通过 JavaScript 管理轨道填充颜色,现在我们来看看与 <form> 相关的 JavaScript:

    const form = document.querySelector('form');
    form.addEventListener('input', event => {
      const formData = Object.fromEntries(new FormData(form));
      console.table(formData);
    

    每当用户与表单互动并对其进行更改时,控制台都会将表单作为对象记录到表格中,以便在提交到服务器之前轻松查看。

    现在您已经知道我是怎么做到的,您会怎么做呢?这会带来一些有趣的组件架构!谁将在其喜爱的框架中实现第一个带有槽的版本?🙂

    让我们拓展方法,了解在 Web 上构建应用的所有方式。 创建一个演示版,在推特上向我发送链接,我会将其添加到下面的社区混剪部分!

    社区混剪作品

  • @tomayac 为复选框标签的悬停区域提供了样式!此版本中的元素(demosource)之间没有悬停间隔。
  • 如未另行说明,那么本页面中的内容已根据知识共享署名 4.0 许可获得了许可,并且代码示例已根据 Apache 2.0 许可获得了许可。有关详情,请参阅 Google 开发者网站政策。Java 是 Oracle 和/或其关联公司的注册商标。

    最后更新时间 (UTC):2021-03-17。

    [[["易于理解","easyToUnderstand","thumb-up"],["解决了我的问题","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["没有我需要的信息","missingTheInformationINeed","thumb-down"],["太复杂/步骤太多","tooComplicatedTooManySteps","thumb-down"],["内容需要更新","outOfDate","thumb-down"],["翻译问题","translationIssue","thumb-down"],["示例/代码问题","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["最后更新时间 (UTC):2021-03-17。"],[],[]]
     
    推荐文章