Форма с наклонной стороны (отзывчивая)

Я пытаюсь создать фигуру, как на изображении ниже, с наклонным краем только на одной стороне (например, на нижней стороне), в то время как другие края остаются прямыми.

CSS div with a slanted side

Я попытался использовать метод border (код приведен ниже), но размеры моей фигуры являются динамическими, и, следовательно, я не могу использовать этот метод.

.shape {
    position: relative;
    height: 100px;
    width: 200px;
    background: tomato;
}
.shape:after {
    position: absolute;
    content: '';
    height: 0px;
    width: 0px;
    left: 0px;
    bottom: -100px;
    border-width: 50px 100px;
    border-style: solid;
    border-color: tomato tomato transparent transparent;
}
<div class="shape">
    Some content
</div>

Ответ 1

Существует много способов создания фигуры с наклонным краем только с одной стороны.

Следующие методы не могут поддерживать динамические размеры, как уже упоминалось в вопросе:

  • Метод граничного треугольника с значениями пикселей для border-width.
  • Линейные градиенты с синтаксисом угла (например, 45deg, 30deg и т.д.).

Ниже описаны методы, которые могут поддерживать динамические размеры.


Метод 1 - SVG

(Совместимость браузера)

SVG можно использовать для создания фигуры либо с помощью polygon, либо path s. В приведенном ниже фрагменте используется polygon. Любое текстовое содержимое может быть расположено поверх формы.

$(document).ready(function() {
  $('#increasew-vector').on('click', function() {
    $('.vector').css({
      'width': '150px',
      'height': '100px'
    });
  });
  $('#increaseh-vector').on('click', function() {
    $('.vector').css({
      'width': '100px',
      'height': '150px'
    });
  });
  $('#increaseb-vector').on('click', function() {
    $('.vector').css({
      'width': '150px',
      'height': '150px'
    });
  });
})
div {
  float: left;
  height: 100px;
  width: 100px;
  margin: 20px;
  color: beige;
  transition: all 1s;
}
.vector {
  position: relative;
}
svg {
  position: absolute;
  margin: 10px;
  top: 0px;
  left: 0px;
  height: 100%;
  width: 100%;
  z-index: 0;
}
polygon {
  fill: tomato;
}
.vector > span {
  position: absolute;
  display: block;
  padding: 10px;  
  z-index: 1;
}
.vector.top > span{
  height: 50%;
  width: 100%;
  top: calc(40% + 5px); /* size of the angled area + buffer */
  left: 5px;  
}
.vector.bottom > span{
  height: 50%;
  width: 100%;
  top: 5px;
  left: 5px;  
}
.vector.left > span{
  width: 50%;
  height: 100%;
  left: 50%; /* size of the angled area */
  top: 5px;  
}
.vector.right > span{
  width: 50%;
  height: 100%;
  left: 5px;
  top: 5px;  
}



/* Just for demo */

body {
  background: radial-gradient(circle at 50% 50%, aliceblue, steelblue);
}

polygon:hover, span:hover + svg > polygon{
  fill: steelblue;
}

.btn-container {
  position: absolute;
  top: 0px;
  right: 0px;
  width: 150px;
}

button {
  width: 150px;
  margin-bottom: 10px;
}

.vector.left{
  clear: both;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="vector bottom">
  <span>Some content</span>
  <svg viewBox="0 0 40 100" preserveAspectRatio="none">
    <polygon points="0,0 40,0 40,100 0,60" />
  </svg>
</div>
<div class="vector top">
  <span>Some content</span>
  <svg viewBox="0 0 40 100" preserveAspectRatio="none">
    <polygon points="0,40 40,0 40,100 0,100" />
  </svg>
</div>
<div class="vector left">
  <span>Some content</span>
  <svg viewBox="0 0 40 100" preserveAspectRatio="none">
    <polygon points="0,0 40,0 40,100 20,100" />
  </svg>
</div>
<div class="vector right">
  <span>Some content</span>
  <svg viewBox="0 0 40 100" preserveAspectRatio="none">
    <polygon points="0,0 20,0 40,100 0,100" />
  </svg>
</div>

<div class='btn-container'>
  <button id="increasew-vector">Increase Width</button>
  <button id="increaseh-vector">Increase Height</button>
  <button id="increaseb-vector">Increase Both</button>
</div>

Ответ 2

Я попытался использовать метод border, но размеры моей фигуры динамические и, следовательно, я не могу использовать этот метод.


Метод 7 - Единицы просмотра (Border Redux)

(Совместимость браузера)

Единицы видовых экранов - отличное новшество в CSS3. Хотя вы обычно можете использовать процентные значения для динамизации ваших свойств, вы не можете сделать это для border-width (или для font-size s).

С помощью блоков Viewport вместо вы можете динамически устанавливать ширину границ вместе с размерами ваших объектов по сравнению с размером области просмотра.

Примечание: процентные значения относятся к родительскому объекту, а не к окну просмотра (видимая область окна).

Чтобы протестировать метод, запустите следующий фрагмент Полная страница и измените его размер как по горизонтали, так и по вертикали.

.shape {
    position: relative;
    height: 20vh;
    width: 40vw;
    background: tomato;
}
.shape:after {
    position: absolute;
    content: '';
    left: 0px;
    right: 0px;
    top: 20vh;
    border-width: 10vh 20vw;
    border-style: solid;
    border-color: tomato tomato rgba(0,0,0,0) rgba(0,0,0,0);
}
<div class="shape">Some content</div>

Ответ 3

Мое решение вдохновлено методом под названием " Метод 7 - Единицы просмотра " Андреа Лигиос, выше на этой странице.

Я также использовал "горизонтальную" единицу для высоты (height:10vw), чтобы сохранить заданные пропорции в трапеции при изменении ширины окна навигации. Мы могли бы назвать этот метод 7b - Ширина области просмотра.

Кроме того, использование двух вложенных элементов div вместо одного и селектора :after after, на мой взгляд, позволяет лучше настраивать стили текстового содержимого (например, text-align и т.д.).

.dtrapz {
  position: relative;
  margin: 10px 40vw;
  width: 0;
  height: 10vw;
  border: none;
  border-right: 20vw solid #f22;
  border-bottom: 5vw solid transparent;
}

.dtcont {
  position: absolute;
  width: 20vw;
  height: 10vw;
  text-align: center;
  color: #fff;/* just aesthetic */
}
<div class="dtrapz">
  <div class="dtcont">Some content</div>
</div>