使用 Sass 制作倾斜角度

发布于 2021-09-24 09:01:15 字数 6758 浏览 1352 评论 0

最近,我不得不在一个网站大量使用倾斜角度作为其设计指南的一部分。倾斜角,是指一个区域它的顶部或底部边缘不是完全水平而是倾斜的。

使用Sass制作倾斜角度

实现这种效果有很多种方法。例如可以将base64编码的图片应用为背景,但这会使得它很难自定义(颜色,角度等)。

另一种方法是倾斜或旋转绝对定位的伪元素,然而倾斜变换是我最不愿意处理的一件事。

使用Sass时,可以使用动态编码生成 SVG 的 Angled Edges库。它能很好的工作,但它需要一个以像素表示的固定宽度和高度,这使我感到有点困扰。

我也真的想知道自己是否能实现和如何实现倾斜角效果。最终我得到了一个自己为之自豪的解决方法,哪怕它可能为简单场景有点过度设计。

是什么样的方法呢?

我的想法是对绝对定位的伪元素使用半透明,一半实心的渐变。渐变的角度定义了倾斜的角度。

background-image: linear-gradient($angle, $color 50%, transparent 50%);

代码被封装在一个mixin里面,它将背景颜色应用到容器中,并基于给定角度生成一个具有正确渐变的伪元素。很简单,可以这样使用:

.container {
  @include tilted($angle: 3deg, $color: rgb(255, 255, 255));
}

我面临的主要问题是计算伪元素的高度。起初,我把它作为mixin的参数,为了计算伪元素的最佳高度而在每一个新角度经历了尝试-错误后,最后放弃了。不理想。

正当我准备翻盘整个事情,为了弄清背后的公式,我决定远离笔记本,带上纸笔开始涂鸦。我花了一段时间(和一些谷歌搜索)去回忆高中学过的三角数学,最后我做到了。

为了避免猜想或提出接近的近似值,伪元素的高度是从给定角度计算得来的。当然,这一切都是用一点Sass和大量几何完成的。

计算伪元素的高度

相信我所说的,这不会太难。我们知道的第一件事是,我们拥有一个全宽的伪元素。渐变线会成为伪元素的对角线,我们最后得到一个矩形三角形。

我们将其命名为ABCC是直角,B是已知角度(参数$angle),因此A=C-B。如图所示,我们尝试计算出b的长度。

使用Sass制作倾斜角度

为此,我们需要求出c的值(渐变线,又称斜边),它是a的长度值除以A角的正弦值(如B=5°,则A=85°)。

c = a / sin(C - B)

接下来,我们必须使用毕达哥拉斯定理(勾股定理):

斜边(与直角相对的一边)边长的平方等于其他两边边长的平方和。

因此,另一边的平方等于斜边的平方减去第三条边的平方。所以b的平方等于c的平方减去a的平方。

b² = c² - a²

最后,b的长度等于c的平方减去a的平方的平方根

b = √(c² - a²)

就是这样。现在我们可以编写一个小的Sass函数,根据给定角度计算伪元素高度。

@function get-tilted-height($angle) {
      $a: (100% / 1%);
      $A: (90deg - $angle);
      $c: ($a / sin($A));
      $b: sqrt(pow($c, 2) - pow($a, 2));
      @return (abs($b) * 1%);
}

注意:pow(),sqrt(),sin() 函数来自 Sassy-Math, Compass or custom sources

编写实现倾斜的混合宏

相信我,我们已经完成了最难的部分。最后要做的是编写实际的tilted()混合宏。它接收一个角度和一个颜色值,并生成伪元素。

@mixin tilted($angle, $color) {
    $height: get-tilted-height($angle);
    position: relative;
    background-color: $color;

    &::before {
      content: '';
      padding-top: $height;
      position: absolute;
      left: 0;
      right: 0;
      bottom: 100%;
      background-image: linear-gradient($angle, $color 50%, transparent 50%);
   }
}

这里要注意几点:混合宏对应容器应用了position:relative,这为伪元素定义了位置环境。当绝对定位或固定定位的元素使用这个混合宏时,也许应该考虑从混合宏中移除这个声明。

这个混合宏将背景颜色同时应用到容器本身及伪元素的渐变,因为它们必须同步。

最后,伪元素的高度必须通过padding-top(或padding-bottom)而不是height来传递。由于高度是基于父元素宽度的百分比来表示的,不能依赖height(因为它是根据父元素的高度来计算的)。

总结和进一步探讨

在本文中,我选择了一个简单的版本的混合宏,这可能缺乏灵活性,但从理论上讲,它可能存在以下问题:

  • 不能在一个已被占用的::before伪元素使用。这时可以通过增加一个可选参数来指定伪元素,默认为before
  • 不能在容器的底部显示一个倾斜角度,因为bottom:0目前已经在mixin 核心里硬编码。这可以通过传递额外的位置到mixin来解决。

此外,我现有的版本使用基于Sass的数学函数,因为它是在Jekyll项目,不允许我扩展Sass层。如果使用node-sass,你可以轻而易举地通过EyeglassSassport将这些函数从 JavaScript 传递到 Sass。这样做无疑更好。

<div class="container">
  <div class="content">
    <h1>Tilted angles in CSS</h1>
    <p>Thanks to Pythagoras Theorem, some gradients and a bit of Sass-powered trigonometry, we can easily created tilted angles with nothing but CSS.</p>
    <pre><code>.container {
  @include tilted(3deg, $color: #fff);
}</code></pre>
    <p>How handy!</p>
  </div>
</div>
/// Computes the height of the tilted pseudo-element based on the given angle
/// using Pythagoras Theorem.
// sin(..), pow(..) and sqrt(..)  functions come from this pen:
// https://codepen.io/HugoGiraudel/pen/rLpPGo
/// @access public
/// @author Hugo Giraudel
/// @param {Angle} $angle - the tilt angle
@function get-tilted-height($angle) {
  $a: (100% / 1%);
  $A: (90deg - $angle);
  $c: ($a / sin($A));
  $b: sqrt(pow($c, 2) - pow($a, 2));

  @return (abs($b) * 1%);
}

/// Apply a tilted effect by generating a pseudo-element with a diagonal
/// splitted background.
/// @access public
/// @author Hugo Giraudel
/// @param {Angle} $angle - the tilt angle
/// @param {Color} $color - the color to be used as background + gradient
/// @param {String} $position ['top'] - either `top` or `bottom`
/// @param {String} $pseudo ['before'] - either `before` or `after`
@mixin tilted($angle, $color, $position: 'top', $pseudo: 'before') {
  $height: get-tilted-height($angle);

  position: relative;
  background-color: $color;

  &::#{$pseudo} {
    content: '';
    padding-top: $height;
    position: absolute;
    left: 0;
    right: 0;

    @if ($position == 'top') {
      bottom: 100%;
      background-image: linear-gradient($angle, $color 50%, transparent 50%);
    } @else {
      top: 100%;
      background-image: linear-gradient($angle, transparent 50%, $color 50%);
    }
  }
}

/*
 * Demo styles
 */

html {
  box-sizing: border-box;
  height: 100%;
}

*, ::before, ::after {
  box-sizing: inherit;
}

body {
  background-color: rgb(223, 231, 238);
  line-height: 1.5;
  font-size: 125%;
  display: flex;
  align-items: flex-end;
  height: 100%;
}

.container {
  @include tilted(3deg, rgb(255, 255, 255));
  padding: 0 1em;
  max-width: 80%;
  margin: 0 auto;
  filter: drop-shadow(0 1em 1em rgba(0, 0, 0, 0.1));
}

.content {
  max-width: 600px;
  margin: 0 auto;
  padding: 0 1em;
}

h1 {
  border-bottom: 3px double deepskyblue;
  padding-bottom: 0.25em;
  margin-bottom: 0.25em;
}

pre {
  background-color: #efefef;
  border: 1px solid rgba(0, 0, 0, 0.1);
  padding: 0.5em;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

清晨说晚安

我之所以活到现在的全部意义,是为了此刻能对你说,我爱你,我会在你身后永远守护你。

0 文章
0 评论
21958 人气
更多

推荐作者

qq_Yqvrrd

文章 0 评论 0

2503248646

文章 0 评论 0

浮生未歇

文章 0 评论 0

养猫人

文章 0 评论 0

第七度阳光i

文章 0 评论 0

新雨望断虹

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文