2018 年的挖角式边角

Avatar of Ana Tudor
Ana Tudor

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费信用额度!

当我看到 Chris 关于 凹槽盒 的文章时,我记得我之前遇到过一个挑战,要求以跨浏览器的方式用 CSS 实现如下所示的设计

The design shows a header box and a 2x2 grid of boxes below, all middle aligned horizontally. There's a line extending from the bottom middle of the header, going in between the two boxes on the row right underneath the header and then growing into a circle whose central point is at equal distance from all four boxes on the 2x2 grid. To accommodate for this pretty big circle, all these boxes have a scooped corner (that's the bottom right corner for the top left box, the bottom left corner for the top right box, the top right corner for the bottom left box and the top left corner for the bottom right box).
挑战的样子。

它看起来与凹槽盒的概念非常相似,只是角现在是挖空的,我们只需要担心每个盒子的一个角。因此,让我们看看如何实现它,如何将该技巧扩展到多个角,会遇到哪些问题以及如何在不影响浏览器支持的情况下解决这些问题。

最初的想法:box-shadow

我们从一个盒子元素开始

<div class='box'></div>

我们可以给它一些尺寸,或者让它的尺寸由内容决定——这并不重要。为简单起见,我们只是在上面设置了 max-widthmin-height。我们还给它一个 outline,以便我们能够看到它的边界。

.box {
  outline: solid 2px;
  max-width: 15em;
  min-height: 10em;
}

接下来,我们将一个正方形的 ::before 伪元素绝对定位,其边长等于角部挖空的直径(或半径 $r 的两倍)。我们还给这个伪元素一个红色的 box-shadow 和一个虚拟的 background(稍后我们将删除它),以便我们能够更好地看到它

$r: 2em;

.box {
  position: relative;
  /* same styles as before */
  
  &:before {
    position: absolute;
    padding: $r;
    box-shadow: 0 0 7px #b53;
    background: #95a;
    content: ''
  }
}

到目前为止,这就是我们拥有的

查看 thebabydino 在 CodePen 上创建的 Pen。(@thebabydino

嗯,它看起来还不够令人兴奋…… 不过!所以让我们继续,通过在上面设置 border-radius: 50% 将这个正方形变成一个圆盘,并给它一个等于其半径 $r 的负 margin,以便它的中心点与父盒子的 (0,0) 点(左上角)重合。我们还在父盒子上设置 overflow: hidden,以便将此伪元素在 .box 外部的任何部分裁剪掉。

$r: 2em;

.box {
  overflow: hidden;
  /* same styles as before */
  
  &:before {
    /* same styles as before */
    margin: -$r;
    border-radius: 50%
  }
}

现在我们开始看到我们一直想要的形状了

查看 thebabydino 在 CodePen 上创建的 Pen。(@thebabydino

但它仍然不是我们想要的。为了达到目的,我们使用 box-shadow 属性的第四个长度值:**扩展半径**。如果您需要复习一下 box-shadow 如何使用这四个值,您可以查看下面的交互式演示

查看 thebabydino 在 CodePen 上创建的 Pen。(@thebabydino

您可能已经猜到我们接下来要做什么了。我们删除虚拟的 background,将前三个 box-shadow 值(xy 偏移量以及模糊半径)设为零,并为最后一个值(扩展半径)使用一个相当大的数字

box-shadow: 0 0 0 300px;

下面的交互式演示显示了如何通过增加扩展半径使其覆盖其父 .box 的越来越多的部分

查看 thebabydino 在 CodePen 上创建的 Pen。(@thebabydino

因此,这里的技巧是拥有足够大的扩展半径以覆盖父元素的其余部分。这样做的好处是我们可以让 box-shadow 半透明或在父 .box 上具有圆角

.box {
  /* same styles as before */
  border-radius: 1em;
  
  &:before {
    /* same styles as before */
    box-shadow: 0 0 0 300px rgba(#95a, .75);
  }
}

查看 thebabydino 在 CodePen 上创建的 Pen。(@thebabydino

当然,就像 Chris 在关于凹槽盒的文章中指出的那样,我们可以将挖空半径设为 CSS 变量,然后从 JavaScript 中轻松修改它。然后一切都会很好地更新,即使我们的盒子里有文本内容也是如此

:root { --r: 50px } 

.box {
  /* same styles as before */
  padding: var(--r);

  &:before {
    /* same styles as before */
    margin: calc(-1*var(--r));
    padding: inherit;
}

请注意,当我们也有文本内容时,我们需要在 ::before 伪元素上设置一个负的 z-index 并明确地将其定位在角部,因为我们现在还在 .box 上有一个 padding 来补偿挖空。

.box {
  /* same styles as before */

  &:before {
    /* same styles as before */
    z-index: -1;
    top: 0;
    left: 0
}

查看 thebabydino 在 CodePen 上创建的 Pen。(@thebabydino

应用此技巧

现在,让我们更进一步,看看如何应用此概念来重现我在开头显示的设计。在这种特定情况下,伪元素圆盘的中心点与盒子角不重合,而是在外部,位于盒子之间的空间中间。

使用的结构非常简单,只是一个 <header> 元素,后面跟着四个 <article> 元素,我在 Pug 循环中生成这些元素

while n--
  article
    h3 #{data[n].name}
    section
      p #{data[n].quote}
      a(href='#') go

我们在 <body> 上使用一个包装 flexbox 布局,<header> 非常宽,并且每行有一个或两个 <article> 元素,具体取决于视口有多宽。

Screenshot of the design implementation in landscape vs. portrait mode. In landscape mode, we have the 4 article boxes arranged as a 2x2 grid. In portrait mode, they're on a 1x4 grid (aka all on a column).
横向(左)与纵向(右)模式。

如果每行只有一个 <article>,则没有挖角式边角,因此其半径为 0px。否则,我们将此半径 --r 设置为非零值。

$min-w: 15rem; /* min width of an article element */
$m: 1rem; /* margin of such an element */

html { --r: 0px; }

article {
  margin: $m;
  min-width: $min-w;
  width: 21em;
}

@media (min-width: 2*($min-w + 2*$m) /* enough for 2 per row */) {
  html { --r: 4rem; }
  
  article { width: 40%; }
}

现在,让我们只考虑每行有两个 <article> 元素的情况(当然,每个元素都有一个挖角式边角,因为这正是我们感兴趣的)。

在第一个元素的情况下,我们从圆盘最左边的限制开始,沿着其父元素的右边缘。到目前为止,它是 left: 100%。为了将圆盘中心点的 x 坐标移动到其父元素的右边缘,我们减去圆盘的半径,这将我们带到 left: calc(100% - var(--r))。但我们不希望它在右边缘,我们希望它向右偏移 <article> 边距 $m,这将我们带到最终值

left: calc(100% - var(--r) + #{$m});

查看 thebabydino 在 CodePen 上创建的 Pen。(@thebabydino

沿着 y 轴,我们从圆盘最顶部的限制开始,沿着其父元素的底边缘——即 top: 100%。为了将圆盘的中心点放在父盒子的底边缘,我们将其向上移动一个半径,这将我们带到 top: calc(100% - var(--r))。最后,我们希望此中心点位于父元素底边缘下方 $m 处,这将给我们最终的垂直偏移量

top: calc(100% - var(--r) + #{$m});

查看 thebabydino 在 CodePen 上创建的 Pen。(@thebabydino

对于第二个 <article>(同一行上的第二个),在垂直偏移量的情况下,我们具有相同的值。

查看 thebabydino 在 CodePen 上创建的 Pen。(@thebabydino

然而,在水平方向上,我们从圆盘的左限制开始,沿着其父元素的左边缘——即 left: 0%。为了将圆盘的中心点放在其父元素的左边缘,我们将其向左移动一个半径 --r,从而得到 left: calc(0% - var(--r))。但是,最终位置位于父元素左边缘左侧 $m

left: calc(0% - var(--r) - #{$m});

查看 thebabydino 在 CodePen 上创建的 Pen。(@thebabydino

对于第三个 <article>(最后一行上的第一个),我们沿 x 轴的偏移量与第一个元素的情况相同。

查看 thebabydino 在 CodePen 上创建的 Pen。(@thebabydino

在垂直方向上,我们从圆盘的顶部限制开始,沿着其父元素的顶部边缘——即 top: 0%。为了将圆盘的中心点放在父元素的顶部边缘,我们将其向上移动一个半径 --r,从而得到 top: calc(0% - var(--r))。但是我们希望它位于父元素顶部边缘上方 $m 处,因此最终的顶部偏移量为

top: calc(0% - var(--r) - #{$m});

查看 thebabydino 在 CodePen 上创建的 Pen。(@thebabydino

对于最后一个(最后一行上的第二个),我们具有与上方的元素相同的水平偏移量,以及与同一行左侧的元素相同的垂直偏移量。

查看 thebabydino 在 CodePen 上创建的 Pen。(@thebabydino

因此,我们的偏移量可以写成

article:nth-of-type(1) { /* 1st */
 left: calc(100%/* 2*50% = (1 + 1)*50% = (1 + i)*50% */ - var(--r) + /* i=+1 */#{$m});
 top:  calc(100%/* 2*50% = (1 + 1)*50% = (1 + j)*50% */ - var(--r) + /* j=+1 */#{$m});
}

article:nth-of-type(2) { /* 2nd */
 left: calc(  0%/* 0*50% = (1 - 1)*50% = (1 + i)*50% */ - var(--r) - /* i=-1 */#{$m});
 top:  calc(100%/* 2*50% = (1 + 1)*50% = (1 + j)*50% */ - var(--r) + /* j=+1 */#{$m});
}

article:nth-of-type(3) { /* 3rd */
 left: calc(100%/* 2*50% = (1 + 1)*50% = (1 + i)*50% */ - var(--r) + /* i=+1 */#{$m});
 top:  calc(  0%/* 0*50% = (1 - 1)*50% = (1 + j)*50% */ - var(--r) - /* j=-1 */#{$m});
}

article:nth-of-type(4) { /* 4th */
 left: calc(  0%/* 0*50% = (1 - 1)*50% = (1 + i)*50% */ - var(--r) - /* i=-1 */#{$m});
 top:  calc(  0%/* 0*50% = (1 - 1)*50% = (1 + j)*50% */ - var(--r) - /* j=-1 */#{$m});
}

这意味着圆盘中心点的位置取决于 <article> 元素之间的间隙(此间隙是我们在其上设置的 margin: $m 的两倍)、圆盘半径 r 以及几个水平和垂直乘数(分别为 --i--j)。这两个乘数最初都为 -1

对于前两个 <article> 元素(2x2 网格的第一行),我们将垂直乘数 --j 更改为 1,因为我们希望圆盘中心点的 y 坐标位于底部边缘下方,而对于奇数元素(第一列),我们将水平乘数 --i 更改为 1,因为我们希望 x 坐标位于右边缘右侧。

html { --i: -1; --j: -1 } /* multipliers initially set to -1 */

h3, section {
  &:before {
    /* set generic offsets */
    top:  calc((1 + var(--j))*50% - var(--r) + var(--j)*#{$m});
    left: calc((1 + var(--i))*50% - var(--r) + var(--i)*#{$m});
  }
}

@media (min-width: 2*($min-w + 2*$m)) {
  article {
    /* change vertical multiplier for first two (on 1st row of 2x2 grid) */
    &:nth-of-type(-n + 2) { --j: 1 }

    /* change horizontal multiplier for odd ones (on 1st column) */
    &:nth-of-type(odd) { --i: 1 }
}

请注意,我们只在前两个 <article> 元素的 <section> 元素上以及最后两个元素的 <h3> 上具有可见的圆盘挖空。因此,对于前两个 <article> 元素,标题的 ::before 伪元素上的半径 --r0,而对于最后两个元素,部分的 ::before 伪元素上的此半径为 0

@media (min-width: 2*($min-w + 2*$m)) {
  article {
    &:nth-of-type(-n + 2) h3, 
    &:nth-of-type(n + 3) section { &:before { --r: 0 ; } }
  }
}

以类似的方式,我们向 <article> 元素的子元素添加了不同的填充

$p: .5rem;

h3, section { padding: $p; }

@media (min-width: 2*($min-w + 2*$m)) {
  article {
    &:nth-of-type(-n + 2) section, 
    &:nth-of-type(n + 3) h3 {
      padding-right: calc(.5*(1 + var(--i))*(var(--r) - #{$m}) + #{$p});
      padding-left: calc(.5*(1 - var(--i))*(var(--r) - #{$m}) + #{$p});
    }
  }
}

这有助于我们获得我们想要的结果

查看 thebabydino 在 CodePen 上创建的 Pen。(@thebabydino

上述演示在所有主要浏览器的当前版本中均有效,如果我们可以使用重复而不是使用 CSS 变量,我们可以将支持一直扩展到 IE9。

上述方法的潜在问题

虽然这是一种快速简便的跨浏览器方法,可以在这种特定情况下获得期望的结果,但我们可能并不总是能如此幸运地使用这种方法。

首先,我们需要为每个挖空的角创建一个伪元素,所以如果我们希望所有角都具有这种效果,则需要引入一个额外的元素。可怜的熊猫。

其次,我们可能并不总是希望使用纯色的background。我们可能希望使用半透明的(如果我们想要多个挖空的角,就会变得很难实现),渐变的(虽然我们可以用box-shadow模拟一些径向渐变,但这不是一个理想的解决方案),甚至是一个图像background(几乎无法实现,唯一的解决方案是使用mix-blend-mode,而这会导致失去对Edge的支持,并且没有优雅的回退方案)。

对于非常大的盒子,我们设置的扩散范围不够怎么办?糟糕。

因此,让我们探索其他更可靠的方法,这些方法具有不同程度的浏览器支持。

灵活性良好的浏览器支持?使用SVG吧!

这可能并不奇怪,但如果我们想要一个灵活且可靠的跨浏览器解决方案,完整的SVG解决方案效果最好。这种解决方案涉及在盒子内容之前使用一个SVG元素。这个SVG包含一个<circle>,我们在这个圆上设置了一个半径r属性。

<div class='box'>
  <svg>
    <circle r='50'/>
  </svg>
  TEXT CONTENT OF BOX GOES HERE
</div>

我们在这个盒子内绝对定位这个SVG,并将其大小调整为完全覆盖其父元素。

.box { position: relative; }

svg {
  position: absolute;
  width: 100%;
  height: 100%;
}

到目前为止,没什么太有趣的,所以让我们给<circle>一个id,并在其他角复制它。

<circle id='c' r='50'/> 
<use xlink:href='#c' x='100%'/> 
<use xlink:href='#c' y='100%'/> 
<use xlink:href='#c' x='100%' y='100%'/> 

请注意,如果我们想要排除一个或多个角,我们只需不复制它到那里。

查看thebabydino在CodePen上的Pen@thebabydino)。

好吧,但我们在这里所做的是在角上创建圆圈,而我们真正想要的是……完全相反的东西!接下来,我们将这些圆圈放在一个<mask>中,覆盖在一个白色、全尺寸(覆盖整个SVG)的矩形上,然后在另一个全尺寸矩形上使用这个mask

<mask id='m' fill='#fff'>
  <rect id='r' width='100%' height='100%'/>
  <circle id='c' r='50' fill='#000'/>
  <use xlink:href='#c' x='100%'/>
  <use xlink:href='#c' y='100%'/>
  <use xlink:href='#c' x='100%' y='100%'/>
</mask>
<use xlink:href='#r' fill='#f90' mask='url(#m)'/>

结果如下所示。

查看thebabydino在CodePen上的Pen@thebabydino)。

如果我们有文本,我们需要根据角半径调整盒子的padding,将其设置为与SVG圆圈的半径相同的值,并使用JavaScript保持它们同步。

查看thebabydino在CodePen上的Pen@thebabydino)。

当然,我们背景矩形的fill不必是纯色。它可以是半透明的(就像上面演示中那样),或者我们可以使用SVG渐变或图案。后者还可以让我们使用一个或多个背景图像。

查看thebabydino在CodePen上的Pen@thebabydino)。

但我来这里是为了CSS糖果!

好吧,很高兴你问!我们可以做很多事情来将遮罩方法的权重从SVG转移到CSS。

遗憾的是,这些方法都不是跨浏览器的,但它们简化了事情,并且绝对值得在不久的将来或更远的将来关注。

改为在HTML元素上使用CSS遮罩

我们在这里所做的是从SVG中移除mask之外的所有内容。然后,从CSS中,我们设置一个background(可以是半透明的、CSS渐变、图像、多个背景的组合……任何CSS可以提供的)和.box元素上的mask属性。

.box {
  /* any kind of background we wish */
  mask: url(#m);
}

请注意,目前只有Firefox支持在HTML元素上设置内联SVG遮罩!

Animated gif. Dragging a slider changes both the r attribute of the circle inside the SVG mask and the padding around the text content inside the box.
使用CSS遮罩直接作用于我们的.box的版本(实时演示,仅限Firefox)。

从CSS设置圆圈半径

这意味着从我们的<circle>中移除r属性,并在CSS中将其设置为与盒子填充相同的变量。

.box { padding: var(--r); }

[id='c'] { r: var(--r); }

这样,当我们更改--r的值时,挖空的半径和.box内容周围的padding都会更新!

请注意,目前只有Blink浏览器支持从CSS设置SVG元素的几何属性!

Screenshot. Shows the corners being scooped out in the version setting the radius of the scoop circle as a CSS variable from the CSS.
使用CSS变量作为<circle>半径的版本(实时演示,仅限Blink)。

结合前两种方法

虽然这会很酷,但遗憾的是,目前在任何浏览器中都无法实现。但好消息是,我们可以做得更好!

使用CSS渐变进行遮罩

请注意,目前Edge根本不支持在HTML元素上使用CSS遮罩,尽管它被列为“开发中”,并且已经出现在about:flags中(目前不起作用)的标志

我们完全放弃SVG部分,开始构建我们的CSS渐变mask。我们使用径向渐变在盒子的角上创建圆圈。以下CSS在盒子的左上角创建了一个半径为--r的圆圈。

.box {
  background: radial-gradient(circle at 0 0, #000 var(--r, 50px), transparent 0);
}

您可以在下面的演示中看到它,我们还在盒子上添加了一个红色的轮廓,以便我们可以看到它的边界。

查看thebabydino在CodePen上的Pen@thebabydino)。

我们对mask使用完全相同的渐变。

.box {
  /* same as before */
  /* any CSS background we wish */
  mask: radial-gradient(circle at 0 0, #000 var(--r, 50px), transparent 0);
}

请注意,WebKit浏览器仍然需要为mask属性添加-webkit-前缀。

然后,我们在其他角添加圆圈。

$grad-list: radial-gradient(circle at   0    0 , #000 var(--r, 50px), transparent 0), 
            radial-gradient(circle at 100%   0 , #000 var(--r, 50px), transparent 0), 
            radial-gradient(circle at   0  100%, #000 var(--r, 50px), transparent 0), 
            radial-gradient(circle at 100% 100%, #000 var(--r, 50px), transparent 0);
.box {
  /* same as before */
  /* any CSS background we wish */
  mask: $grad-list
}

这令人难以置信地重复,要么需要写很多代码,要么需要复制粘贴很多,所以让我们看看我们能做些什么。

首先,我们为停止列表使用CSS变量。这消除了生成的CSS中的重复。

$grad-list: radial-gradient(circle at   0    0 , var(--stop-list)), 
            radial-gradient(circle at 100%   0 , var(--stop-list)), 
            radial-gradient(circle at   0  100%, var(--stop-list)), 
            radial-gradient(circle at 100% 100%, var(--stop-list));

.box {
  /* same as before */
  /* any CSS background we wish */
  --stop-list: #000 var(--r, 50px), transparent 0;
  mask: $grad-list;
}

但这并没有好多少,所以让我们在循环中生成角。

$grad-list: ();

@for $i from 0 to 4 {
  $grad-list: $grad-list, 
    radial-gradient(circle at ($i%2)*100% floor($i/2)*100%, var(--stop-list));
}

.box {
  /* same as before */
  /* any CSS background we wish */
  --stop-list: #000 var(--r, 50px), transparent 0;
  mask: $grad-list;
}

就代码而言,这要好得多,因为现在我们不必多次编写任何内容,并且避免了以后可能无法在所有地方更新的风险。但到目前为止的结果并非我们想要的结果。

Screenshot. Shows how the code above masks out everything but the quarter circles in the corners (the opposite of what we want).
上面代码的结果(实时演示,目前不支持Edge)。

在这里,我们剪掉了除了角之外的所有内容,这与我们想要的结果相反。

我们可以做的一件事是反转渐变,使角圆圈transparent,其余部分为black,使用

--stop-list: transparent var(--r, 50px), #000 0;

当我们只对一个角使用一个渐变时,这可以解决问题。

Screenshot. Shows the result when we have an abrupt change from transparent to black in a masking radial gradient at a corner: a quarter circle gets masked out at that corner.
仅使用一个渐变的结果(实时演示,目前不支持Edge)。

但是,当我们将所有四个(甚至只是两个)叠加在一起时,我们会得到一个与盒子大小相同的black矩形作为mask,这意味着实际上没有任何内容被遮罩了。

Animated gif. When the mask's gradient list is empty, no masking happens. When we add full size radial gradient layer with a transparent quarter circle in the top left corner, this masks out the area of that transparent quarter circle as these masks are alpha masks, giving each pixel of the element the mask is applied to the alpha of the corresponding mask pixel at that position. When we add another such gradient with a transparent quarter circle at another corner, this covers the transparent corner of the first layer and we can see the non-transparent corner of the first layer through its own transparent corner. So now the resulting masks has no more trnsparent pixels and nothing gets masked out anymore.
分层遮罩渐变(实时演示,目前不支持Edge)。

因此,我们将每个渐变限制在盒子的四分之一——width50%height50%,从而为每个获得25%(四分之一)的区域。

Illustration. Shows the full mask area being divided into 4 quarters, each being 50% of the width and 50% of the height. The first is in the top left corner, the second in the top right corner, the third in the bootom left corner and th fourth in the bottom right corner.
我们的遮罩,分成四个部分(实时)。

这意味着我们还需要设置mask-size50% 50%mask-repeatno-repeat,并将每个mask-image定位到所需的角。

$grad-list: ();

@for $i from 0 to 4 {
  $x: ($i%2)*100%;
  $y: floor($i/2)*100%;
  $grad-list: $grad-list 
              radial-gradient(circle at $x $y, var(--stop-list)) /* mask image */
              $x $y; /* mask position */
}

.box {
  /* same as before */
  /* any CSS background we wish */
  --stop-list: transparent var(--r, 50px), #000 0;
  mask: $grad-list;
  mask-size: 50% 50%;
  mask-repeat: no-repeat;
}

请注意,WebKit浏览器仍然需要为mask属性添加-webkit-前缀。

但这里最大的问题是……一般来说,除法和四舍五入的问题——我们的四个部分加在一起并不总是能够再次构成一个整体,因此它们之间会出现间隙。

Annotated screenshot. Shows and highlights the gaps in between the four quarters.
遗憾的是,四个部分之间可能会出现间隙(实时演示)。

好吧,我们并不是不能用细长的linear-gradient()条纹来覆盖这些间隙,或者将mask-size增加到比如51%

Screenshot showing we don't have gaps in between the four quarters anymore after increasing their mask-size by 1%.
为每个渐变层增加mask-size可以解决间隙问题(在线演示)。

但是,有没有更优雅的方法呢?

嗯,如果我们在恢复到全尺寸渐变层时将其设置为intersect,则可以使用mask-composite属性来帮助我们。

$grad-list: ();

@for $i from 0 to 4 {
  $grad-list: $grad-list, 
              radial-gradient(circle at ($i%2)*100% floor($i/2)*100%, var(--stop-list));
}

.box {
  /* same as before */
  /* any CSS background we wish */
  --stop-list: transparent var(--r, 50px), #000 0;
  mask: $grad-list;
  mask-composite: intersect;
}

这非常酷,因为它是一个纯CSS解决方案,无需SVG,但不太好的消息是,支持仅限于Firefox 53+。

Screenshot. Shows that when using mask-composite: intersect, the parts that don't belong to the intersection of all the layers (are not common) gat masked out. That means the quarter circles at the four corners in our case.
使用mask-composite: intersect的结果(在线演示)。

但是,我们至少有非标准的-webkit-mask-composite替代方案(取不同的值!)用于WebKit浏览器。因此,这比我们在涉及挖角时拥有的最终选项的支持要好得多。

corner-shape选项

Lea Verou大约五年前提出了这个想法,甚至为它创建了一个预览页面。遗憾的是,它不仅还没有被任何浏览器实现,而且规范在此期间也没有取得太大进展。它仍然是未来需要牢记的东西,因为它提供了很大的灵活性,代码很少——重新创建我们的效果只需要以下内容

padding: var(--r);
corner-shape: scoop;
border-radius: var(--r);

没有标记冗余,没有冗长的渐变列表,只有这段非常简单的CSS代码。也就是说……当它最终得到浏览器的支持时!