Как расположить наклонную / скошенную форму неизвестной высоты в CSS? - PullRequest
1 голос
/ 06 августа 2020

Проблема

Мне нужно закодировать дизайн, как на изображении ниже, в CSS. В дополнение к чистому CSS в моем распоряжении также Sass.

Обратите внимание, что решение должно быть отзывчивым. Угол фиксирован (14 градусов), а расстояние x - нет, потому что оно зависит от высоты контейнера (которая будет отличаться на экранах разной ширины).

Layout with 2 tilted areas

Fixed height

The fixed height version is not a problem:

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 не может узнать высоту контейнера.

Вопрос

Знаете ли вы о каком-либо возможном решении этой проблемы?

1 Ответ

2 голосов
/ 06 августа 2020

Одна из идей - рассмотреть большой элемент треугольной angular формы, где ширина / высота задаются с учетом угла, который вы хотите использовать.

Вот пример для иллюстрации:

.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>
...