使用自定义属性的上下文颜色实用程序类

Avatar of Christopher Kirk-Nielsen
Christopher Kirk-Nielsen

DigitalOcean 提供适用于您旅程各个阶段的云产品。立即开始使用 $200 免费积分!

在 CSS 中,我们可以访问 currentColor,它非常有用。遗憾的是,我们无法访问类似 currentBackgroundColor 的东西,而且 color-mod() 函数还需要一段时间才能实现。

话虽如此,我相信我不孤单,我想根据上下文样式化一些链接,并在链接悬停或聚焦时反转颜色。借助 CSS 自定义属性和一些简单的实用程序类,我们可以实现非常强大的效果,这得益于我们样式的级联特性。

查看 CodePen 上的示例
使用实用程序类和自定义属性上下文着色链接
,作者:Christopher Kirk-Nielsen (@chriskirknielsen)
CodePen 上。

为了实现这一点,我们需要使用实用程序类(包含我们的自定义属性)来指定我们的文本和背景颜色。然后,我们将使用这些类来定义下划线的颜色,下划线将在悬停时扩展为完整的背景。

让我们从我们的标记开始

<section class="u-bg--green">
  <p class="u-color--dark">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, <a href="#">sed do eiusmod tempor incididunt</a> ut labore et dolore magna aliqua. Aliquam sem fringilla ut morbi tincidunt. Maecenas accumsan lacus vel facilisis. Posuere sollicitudin aliquam ultrices sagittis orci a scelerisque purus semper.
  </p>
</section>

这将为我们提供一个包含段落的块,该段落包含一个链接。让我们设置我们的实用程序类。我将定义 我在 Color Hunt 上找到的四种颜色。我们将为 color 属性创建一个类,为 background-color 属性创建一个类,它们将分别包含一个用于分配颜色值的变量(分别为 --c--bg)。因此,如果我们要定义 green 颜色,我们将拥有以下内容

.u-color--green {
  --c: #08ffc8;
  color: #08ffc8;
}

.u-bg--green {
  --bg: #08ffc8;
  background-color: #08ffc8;
}

如果您是 Sass 用户,您可以使用地图自动执行此过程,并循环遍历值以自动创建颜色和背景类。请注意,这不是必需的,它只是一种自动创建许多颜色相关实用程序类的方法。这非常有用,但要跟踪您的使用情况,以便您不会,例如,创建七个从未在您的网站上使用的背景类。话虽如此,以下是生成我们类的 Sass 代码

$colors: ( // Define a named list of our colors
  'green': #08ffc8,
  'light': #fff7f7,
  'grey': #dadada,
  'dark': #204969
);

@each $n, $c in $colors { // $n is the key, $c is the value
  .u-color--#{$n} {
    --c: #{$c};
    color: #{$c};
  }

  .u-bg--#{$n} {
    --bg: #{$c};
    background-color: #{$c};
  }
}

但是,如果我们在标记中忘记应用实用程序类会怎样?--c 变量将自然使用 currentColor... --bg 也是如此!让我们定义一个顶级默认值以避免这种情况

html {
  --c: #000000;
  --bg: #ffffff;
}

酷!现在我们只需要样式化我们的链接即可。在本文中,我们将使用我们可靠的 <a> 元素来样式化所有链接,但您也可以轻松添加一个 .fancy-link 之类的类。

此外,您可能知道,链接应该按照“LoVe-HAte”顺序进行样式化::link:visited:hover(和 :focus!)以及 :active。我们可以使用 :any-link,但浏览器支持 并不像 CSS 自定义属性那样好。(如果情况相反,这将不是什么大问题。)

我们可以通过为较旧的浏览器提供可接受的体验,然后检查自定义属性支持来开始声明我们链接的样式

/* Styles for older browsers */
a {
  color: inherit;
  text-decoration: underline;
}

a:hover,
a:focus,
a:active {
  text-decoration: none;
  outline: .0625em solid currentColor;
  outline-offset: .0625em;
}

a:active {
  outline-width: .125em;
}

@supports (--a: b) { /* Check for CSS variable support */
  /* Default variable values */
  html {
    --c: #000000;
    --bg: #ffffff;
  }
  
  a {
    /*
      * Basic link styles go here...
      */
  }
}

接下来,让我们创建基本的链接样式。我们将使用自定义属性来使我们的样式尽可能DRY

首先,我们需要设置我们的变量。我们想要定义一个 --space 变量,该变量将用于各种属性,以在文本周围添加一些空间。链接的颜色也将使用 --link-color 在变量中定义,默认值为 currentColor。伪下划线将使用背景图像生成,该图像的大小将根据 --bg-size 的状态进行调整,默认情况下设置为使用 --space 值。最后,为了给这个过程增添一些乐趣,我们还将在链接处于 :active 状态时使用 box-shadow 模拟链接周围的边框,因此我们将它的尺寸定义为 --shadow-size,在其非活动状态下设置为 0。这将为我们提供

--space: .125em;
--link-color: currentColor;
--bg-size: var(--space);
--shadow-size: 0;

我们首先需要调整回退样式。我们将设置 color 以使用我们的自定义属性,并删除默认下划线

color: var(--link-color);
text-decoration: none;

接下来,让我们创建我们的伪下划线。该图像将是一个线性渐变,具有两个相同的起点和终点:文本的颜色 --c。我们确保它只在水平方向上重复,使用 background-repeat: repeat-x;,并将其放置在元素的底部,使用 background-position: 0 100%;。最后,我们给出它的尺寸,在水平方向上为 100%,在垂直方向上为 --bg-size 的值。最终我们将得到以下内容

background-image: linear-gradient(var(--c, currentColor), var(--c, currentColor));
background-repeat: repeat-x;
background-position: 0 100%;
background-size: 100% var(--bg-size);

为了我们的 :active 状态,让我们也定义一个阴影框,它将不存在,但有了我们的变量,它就可以活跃起来:box-shadow: 0 0 0 var(--shadow-size, 0) var(--c);

这就是大部分基本样式。现在,我们需要做的是根据链接状态为我们的变量分配新值。

:link:visited 是用户在链接处于“空闲”状态时看到的内容。由于我们已经设置好了一切,所以这是一个简短的规则集。虽然从技术上讲,我们可以跳过此步骤并在 --link-color 的初始分配中声明 --c 变量,但我在这里分配它是为了使我们样式的每个步骤都清晰明了

a:link,
a:visited {
  --link-color: var(--c);
}

现在链接看起来很酷,但如果我们与它进行交互,什么也不会发生... 让我们接下来创建这些样式。需要发生两件事:背景必须占据所有可用高度( 100%),并且文本颜色必须更改为背景颜色,因为背景是文本颜色(令人困惑,对吧?)。第一个很简单:--bg-size: 100%;。对于文本颜色,我们分配 --bg 变量,如下所示:--link-color: var(--bg);。加上我们的伪类选择器,我们最终得到

a:hover,
a:focus,
a:active {
    --bg-size: 100%;
    --link-color: var(--bg);
}

看看那个下划线在悬停或聚焦时变成了完整的背景!作为奖励,我们可以在单击链接时添加一个模拟边框,方法是增加 --shadow-size,我们的 --space 变量将再次派上用场

a:active {
  --shadow-size: var(--space);
}

我们现在几乎完成了!但是,它看起来有点太通用,所以让我们添加一个过渡、一些填充和圆角,并确保如果链接跨越多行,它看起来也很不错!

对于过渡,我们只需要动画化 colorbackground-sizebox-shadow。持续时间由您决定,但考虑到链接通常大约 20 像素高,我们可以设置一个较小的持续时间。最后,为了使它看起来更平滑,让我们使用 ease-in-out 缓动。总结起来就是

transition-property: color, background-size, box-shadow;
transition-duration: 150ms;
transition-timing-function: ease-in-out;
will-change: color, background-size, box-shadow; /* lets the browser know which properties are about to be manipulated. */

接下来,我们将 --space 变量分配给 paddingborder-radius,但不要担心前者——因为我们没有将其定义为 inline-block,所以填充不会影响我们文本块的垂直节奏。这意味着您可以调整背景的高度,而无需担心行间距!(只要确保测试您的值)

padding: var(--space);
border-radius: var(--space);

最后,为了确保样式在多行上正确应用,我们只需要添加 box-decoration-break: clone;(以及前缀,如果您需要的话),就完成了。

完成后,我们应该拥有以下样式

/* Styles for older browsers */
a {
  color: inherit;
  text-decoration: underline;
}

a:hover,
a:focus,
a:active {
  text-decoration: none;
  outline: .0625em solid currentColor;
  outline-offset: .0625em;
}

a:active {
  outline-width: .125em;
}

/* Basic link styles for modern browsers */
@supports (--a: b) {
  /* Default variable values */
  html {
    --c: #000000;
    --bg: #ffffff;
  }
  
  a {
    /* Variables */
    --space: .125em;
    --link-color: currentColor;
    --bg-size: var(--space);
    --shadow-size: 0;

    /* Layout */
    padding: var(--space); /* Inline elements won't affect vertical rhythm, so we don't need to specify each direction */

    /* Text styles */
    color: var(--link-color);/* Use the variable for our color */
    text-decoration: none; /* Remove the default underline */

    /* Box styles */
    border-radius: var(--space); /* Make it a tiny bit fancier &#x2728; */
    background-image: linear-gradient(var(--c, currentColor), var(--c, currentColor));
    background-repeat: repeat-x;
    background-position: 0 100%;
    background-size: 100% var(--bg-size);
    box-shadow: 0 0 0 var(--shadow-size, 0) var(--c, currentColor); /* Used in the :active state */
    box-decoration-break: clone; /* Ensure the styles repeat on links spanning multiple lines */

    /* Transition declarations */
    transition-property: color, background-size, box-shadow;
    transition-duration: 150ms;
    transition-timing-function: ease-in-out;
    will-change: color, background-size, box-shadow;
  }

  /* Idle states */
  a:link,
  a:visited {
    --link-color: var(--c, currentColor); /* Use --c, or fallback to currentColor */
  }

  /* Interacted-with states */
  a:hover,
  a:focus,
  a:active {
    --bg-size: 100%;
    --link-color: var(--bg);
  }

  /* Active state */
  a:active {
    --shadow-size: var(--space); /* Define the box-shadow size */
  }
}

当然,它比仅仅有一个下划线更复杂,但与允许您始终访问文本和背景颜色的实用程序类一起使用,它是一个非常不错的渐进增强。

您可以使用三种变量为每种颜色进行增强,无论是 rgb 还是 hsl 格式,以调整不透明度等。您还可以添加一个 text-shadow 来模拟 text-decoration-skip-ink