【问题标题】:How to position a tilted/skewed shape of unknown height in CSS?如何在 CSS 中定位未知高度的倾斜/倾斜形状?
【发布时间】:2020-08-08 01:28:27
【问题描述】:

问题

我需要在 CSS 中编写如下图所示的设计。除了纯 CSS,我还可以使用 Sass。

请注意,解决方案需要具有响应性。角度是固定的(14度),而距离x不是,因为它取决于容器的高度(不同的屏幕宽度会有所不同)。

固定高度

定高版本没问题:

HTML

<section class="container">
  <p class="left">
    Some text spanning multiple lines
  </p>
  <p class="right">
    Some text spanning multiple lines
  </p>
</section>

CSS

@use "sass:math";

$trapezium-skew-angle: -14deg;

@mixin orange-background {
  position: relative;

  // Needs to use pseudo-element to be able to render it
  // below the trapezium's layer
  &::before {
    z-index: -1;
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    background-color: orange;
  }
}

@function trapezium-shift($trapezium-height) {
  @return (-1 * math.tan($trapezium-skew-angle) * $trapezium-height) / 2;
}

@mixin trapezium($height, $width) {
  overflow: hidden;
  position: relative;

  &::after {
    z-index: -1;
    content: "";
    display: block;
    position: absolute;
    left: -1 * trapezium-shift($height);
    top: 0;
    bottom: 0;
    width: $width;
    background-color: blue;
    transform: skew($trapezium-skew-angle);
  }
}

@mixin column {
  outline: 1px dashed black;
  padding: 4rem;
  width: 50%;
}

.container {
  @include orange-background;
  
  display: flex;
  flex-flow: row nowrap;
  height: 300px;
}

.left {
  @include column;
  @include trapezium($height: 300px, $width: 50%);
}

.right {
  @include column;
}

响应能力

问题是我的实现需要响应。当屏幕高度发生变化时,容器的高度也会发生变化,trapezium-shift 的值也会随之变化(在图片上标记为 x)。 Sass 在构建时运行,因此 Sass 无法知道容器的高度。

问题

您知道任何可能的解决方案吗?

【问题讨论】:

  • 需要固定角度还是距离?
  • @TemaniAfif 角度需要固定,距离x是动态的。我会把它添加到问题中。

标签: css layout sass css-transforms


【解决方案1】:

一个想法是考虑一个三角形的大元素,其中宽度/高度是根据您要使用的角度来设置的。

这里有一个例子来说明:

.container {
  display: flex;
  height: 80vh; /* dynamic height */
  background:blue;
  overflow:hidden; /* hide the overflow of the big shape */
  color:#fff;
  font-size:25px;
}
.container > * {
  outline: 1px dashed black;
  padding: 4rem;
  width: 50%;
  margin:0;
  box-sizing:border-box;
}
.container > *:last-child {
  background:orange;
  position: relative;
}
.container > *:last-child::before {
  content:"";
  position:absolute;
  right:calc(100% - 0.5px); /* a litte less than 100% to avoid a gap issue */
  top:0;
  height:130vh; /* a big height, 100vh should be enough but a bit bigger won't hurt */
  width:calc(130vh * 0.249328); /* height x tan(14deg) */
  background:inherit;
  clip-path:polygon(0 100%,100% 100%,100% 0); /* triangle shape */
  
  opacity:0.9; /* to illustrate the shape */
}

body {
  margin:0;
}
<section class="container">
  <p class="left">
    Some text spanning multiple lines
  </p>
  <p class="right">
    Some text spanning multiple lines
  </p>
</section>

使用相同技巧但使用box-shadow 和更少代码的另一个想法:

.container {
  display: flex;
  height: 80vh; /* dynamic height */
  background:blue;
  overflow:hidden; /* hide the overflow of the big shape */
  color:#fff;
  font-size:25px;
}
.container > * {
  outline: 1px dashed black;
  padding: 4rem;
  width: 50%;
  margin:0;
}
.container > *:last-child {
  background:orange;
  box-shadow:0 0 0 100vw orange; /* a very big box shadow*/
  clip-path:polygon(0 0,100% 0, 100% 150vh,calc(-0.249328 * 150vh) 150vh); 
  /*  the clip-path will cut a shape like below
            (0 0)   _______  (100% 0)
                   /       |
                  /        | <--- the real content end here, below is overflowing  
      (X 150vh)  /_________| (100% 150vh)
      
      X = 0 - tan(14deg)*150vh
  */
}

body {
  margin:0;
}
<section class="container">
  <p class="left">
    Some text spanning multiple lines
  </p>
  <p class="right">
    Some text spanning multiple lines
  </p>
</section>

更新

第一个代码不带clip-path以获得更好的支持:

.container {
  display: flex;
  height: 80vh; /* dynamic height */
  background:blue;
  overflow:hidden; /* hide the overflow of the big shape */
  color:#fff;
  font-size:25px;
}
.container > * {
  outline: 1px dashed black;
  padding: 4rem;
  width: 50%;
  margin:0;
  box-sizing:border-box;
}
.container > *:last-child {
  background:orange;
  position: relative;
}
.container > *:last-child::before {
  content:"";
  position:absolute;
  right:calc(100% - 0.5px); /* a litte less than 100% to avoid a gap issue */
  top:0;
  height:130vh; /* a big height, 100vh should be enough but a bit bigger won't hurt */
  width:calc(130vh * 0.249328); /* height x tan(14deg) */
  background:linear-gradient(to bottom right,transparent 49.5%,orange 50%); /* triangle shape */
  
  opacity:0.9; /* to illustrate the shape */
}

body {
  margin:0;
}
<section class="container">
  <p class="left">
    Some text spanning multiple lines
  </p>
  <p class="right">
    Some text spanning multiple lines
  </p>
</section>

【讨论】:

  • 所以我们的想法是创建比它需要的更高的倾斜形状,然后使用clip-path 剪裁它的高度,对吧?我只是还不明白,你是如何做到水平位置正确的,但我还在读……
  • @RobertKusznier 这很容易,首先将其视为一个矩形..您使用 right:100% 和 top:0 将其放置在元素的左侧,然后您制作一个很大的高度以溢出并计算考虑高度的宽度,最后我在对角线上切割形状以获得我的三角形
  • @RobertKusznier 我还用更少的代码添加了另一个想法
  • 是的,我现在看起来一切都清楚了。唯一的问题是,从我看到的 clip-path 直到 2020 年 1 月,Edge 才支持:caniuse.com/#search=clip-path :/
  • @RobertKusznier 我的意思是上次更新,答案中有 3 个片段
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 2017-05-18
  • 2019-12-15
  • 2016-12-23
  • 1970-01-01
  • 2014-06-04
  • 1970-01-01
相关资源
最近更新 更多