难题

半透明颜色最初的使用场景之一就是作为背景。将其叠放在照片类或其他花哨的背层之上,可以减少对比度,确保文本的可读性。在传统的平面设计中,这个问题的解决方案通常是把文本层所覆盖的那部分图片区域作模糊处理。

借助 blur() 滤镜,我们在 CSS 中获得了对元素进行模糊处理的能力。如果直接使用 blur() 滤镜,整个元素都会被模糊,文本反而变得更加无法阅读了。有没有某种方法可以只对元素的背层(即被该元素遮住的那部分背景)应用这个滤镜呢?

解决方案

不能直接对元素本身进行模糊处理,就对一个伪元素进行处理,然后将其定位到元素的下层,它的背景将会无缝匹配 <body> 的背景。

<style>
    body {
        min-height: 100vh;
        box-sizing: border-box;
        margin: 0;
        padding-top: calc(50vh - 6em);
        font: 150%/1.6 Baskerville, Palatino, serif;
    }

    body, main::before {
        background: url("1.jpg") 0 / cover fixed;
    }

    main {
        position: relative;
        margin: 0 auto;
        padding: 1em;
        max-width: 23em;
        background: hsla(130, 72%, 24%, 0.25) border-box;
        overflow: hidden;
        border-radius: .3em;
        box-shadow: 0 0 0 1px hsla(0, 0%, 100%, .3) inset,
            0 .5em 1em rgba(0, 0, 0, 0.6);
        text-shadow: 0 1px 1px hsla(249, 64%, 23%, 0.3);
    }

    main::before {
        content: '';
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        margin: -30px;
        z-index: -1;
        -webkit-filter: blur(20px);
        filter: blur(20px);
    }

    blockquote {
        font-style: italic
    }

    blockquote cite {
        font-style: normal;
    }
</style>

<body>
    <main>
        <blockquote>“The only way to get rid of a temptation is to yield to it. Resist it, and your soul grows sick with
            longing for the things it has forbidden to itself, with desire for what its monstrous laws have made
            monstrous and unlawful.”</em>
            <footer><cite>Oscar Wilde, The Picture of Dorian Gray</cite></footer>
        </blockquote>
    </main>
</body>
复制代码

折角效果

难题

把元素的一个角(通常是右上角或右下角)处理为类似折角的形状,再配上或多或少的拟物样式,这种效果已经成为一种非常流行的装饰手法。

已实现的方法的原理通常是在右上角增加两个三角形:一个三角形用来体现折页的形状,另一个白色的三角形遮住元素的一角,用来模拟翻折所产生的缺口。这两个三角形通常都是由经典的边框技巧来生成的。

但是,当折角元素下不是纯色或者折角不是45°时,已有的方案就不能满足了。

45°折角的解决方案

在矩形的右上角创建一个大小为 0.5em 的斜面切角,代码为:

background: yellowgreen; /* 回退样式 */
background:
    linear-gradient(-135deg, transparent 2em, yellowgreen 0);
复制代码

接下来所需要做的就是增加一个暗色的三角形来实现翻折效果。实现方法是增加另一层渐变来生成这个三角形并将其定位在右上角,这样就可以通过 background-size 来控制折角大小。

background: yellowgreen; /* 回退样式 */
background:
    linear-gradient(to left bottom,transparent 50%, rgba(0,0,0,.4) 0) no-repeat 100% 0 / 2em 2em,
    linear-gradient(-135deg, transparent 2em, yellowgreen 0);
复制代码

但是,看到折角并不是所期望的样子,第二层渐变中的 2em 折角尺寸是写在色标中的,因此它是沿着渐变轴进行度量的,是对角线尺寸;而 background-size 中的 2em 长度是背景贴片的宽度和高度,是在水平和垂直方向上进行度量的。因此为了使两者对齐:

  1. 如果要保留对角线的 2em 长度,就要将 background-size 乘以 2 。
  2. 如果要保留水平和垂直方向上的 2em 长度,就要用切角渐变的角标位置值除以2\sqrt{2}2

因为 background-size 使用了两次长度,因此使用第二种方案更合适,因此其值为22\frac{2}{\sqrt{2}}22

background: yellowgreen; /* 回退样式 */
background:
    linear-gradient(to left bottom,transparent 50%, rgba(0,0,0,.4) 0) no-repeat 100% 0 / 2em 2em,
    linear-gradient(-135deg, transparent 1.4em, yellowgreen 0);
复制代码

其他角度的解决方案

.note {
    width: 150px;
    height: 120px;
    position: relative;
    background: yellowgreen;
    /* 回退样式 */
    background:
        linear-gradient(-150deg,
        transparent 1.5em, yellowgreen 0);
    border-radius: .5em;
}

.note::before {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    background: linear-gradient(to left bottom,
        transparent 50%, rgba(0, 0, 0, .2) 0, rgba(0, 0, 0, .4)) 100% 0 no-repeat;
    width: 1.73em;
    height: 3em;
    transform: translateY(-1.3em) rotate(-30deg);
    transform-origin: bottom right;
    border-bottom-left-radius: inherit;
    box-shadow: -.2em .2em .3em -.1em rgba(0, 0, 0, .15);
}
复制代码

mixin的写法

@mixin folded-corner($background, $size, $angle: 30deg) {
    position: relative;
    background: $background;
    /* 回退样式 */
    background:
        linear-gradient($angle - 180deg,
        transparent $size, $background 0);
    border-radius: .5em;
    $x: $size / sin($angle);
    $y: $size / cos($angle);

    &::before {
        content: '';
        position: absolute;
        top: 0;
        right: 0;
        background: linear-gradient(to left bottom,
            transparent 50%, rgba(0, 0, 0, .2) 0,
            rgba(0, 0, 0, .4)) 100% 0 no-repeat;
        width: $y;
        height: $x;
        transform: translateY($y - $x) rotate(2*$angle - 90deg);
        transform-origin: bottom right;
        border-bottom-left-radius: inherit;
        box-shadow: -.2em .2em .3em -.1em rgba(0, 0, 0, .2);
    }
}

/* 当调用时... */
.note {
    @include folded-corner(#58a, 2em, 40deg);
}