Динамическое выравнивание псевдоэлемента по родительской высоте

#html #css #bootstrap-4

#HTML #css #css-формы

Вопрос:

Я пытаюсь создать метку стрелки, используя css :after

 .one-line {
  font-size: 2em;
  width: 150px;
  min-height: 50px;
  height: auto;
  background: blue;
  margin: 5px;
  position: relative;
  color: #fff;
}

.one-line:after {
  content: '';
  display: block;
  position: absolute;
  top: 0;
  left: 100%;
  width: 0;
  height: 0;
  border-top: 25px solid transparent;
  border-bottom: 25px solid transparent;
  border-left: 25px solid red;
}  
 <div class="one-line">text<br>text<br></div>  

Я хочу, чтобы элемент after имел ту же высоту, что и родительский, как я могу это сделать с помощью css или js?

Примечание: текст внутри метки заполняется динамически. [Максимальная длина текста: 2 строки]

Как я думаю, может оказаться невозможным настроить его на любую высоту родительского элемента. В настоящее время я пытаюсь настроить его как для одной, так и для двух строк текста.

Комментарии:

1. это хороший вопрос, потому что, зная, что элемент :before не является элементом dom, поэтому к нему не может быть доступа с помощью js (чтобы установить границы bottom и top = height div / 2). также добавление тега стиля прагматично работает только для одного div (в случае нескольких div с одним и тем же классом …)

Ответ №1:

Вот решение с использованием clip-path . Идея состоит в том, чтобы использовать значения % в полигоне, чтобы показывать только необходимую форму, и это всегда будет работать независимо от высоты:

 .one-line {
  font-size: 2em;
  width: 150px;
  min-height: 50px;
  height: auto;
  background: blue;
  margin: 5px;
  position: relative;
  color: #fff;
}

.one-line:after {
  content: '';
  display: block;
  position: absolute;
  top: 0;
  bottom: 0;
  width: 25px;
  right: -25px;
  background: red;
  -webkit-clip-path: polygon(100% 50%, 0 0, 0 100%);
  clip-path: polygon(100% 50%, 0 0, 0 100%);
}  
 <div class="one-line">text<br>text<br></div>
<div class="one-line">text<br>text<br>text<br></div>

<div class="one-line">text</div>

<div class="one-line">text<br>text<br>text<br>text<br>text<br>text<br>text<br></div>  

Вот еще одно решение, которое использует оба псевдоэлемента и некоторое косое преобразование для создания стрелки. Вы заметите, что этот элемент сохранит соотношение стрелки.

 .one-line {
  font-size: 2em;
  width: 150px;
  min-height: 50px;
  height: auto;
  background: blue;
  margin: 5px;
  position: relative;
  color: #fff;
}

.one-line:after {
  content: '';
  display: block;
  position: absolute;
  top: 0;
  height: 50%;
  width: 50%;
  right: -25px;
  background: red;
  transform: skewX(20deg) translateX(-33%);
  transform-origin: top;
  z-index: -1;
}

.one-line:before {
  content: '';
  display: block;
  position: absolute;
  bottom: 0;
  height: 50%;
  width: 50%;
  right: -25px;
  background: red;
  transform: skewX(-20deg) translateX(-33%);
  transform-origin: bottom;
  z-index: -1;
}  
 <div class="one-line">text<br>text<br></div>
<div class="one-line">text<br>text<br>text<br></div>

<div class="one-line">text</div>

<div class="one-line">text<br>text<br>text<br>text<br>text<br>text<br>text<br></div>  

Другой способ только с одним псевдоэлементом и linear-gradient .

 .one-line {
  font-size: 2em;
  width: 150px;
  min-height: 50px;
  height: auto;
  background: blue;
  margin: 5px;
  position: relative;
  color: #fff;
}

.one-line:after {
  content: '';
  display: block;
  position: absolute;
  top: 0;
  height: 100%;
  width: 50px;
  right: -50px;
  background: 
   linear-gradient(to bottom left, transparent 49.4%, red 50%) top, 
   linear-gradient(to top left,    transparent 49.4%, red 50%) bottom;
  background-size:100% 50.2%;
  background-repeat:no-repeat;
}  
 <div class="one-line">text<br>text<br></div>
<div class="one-line">text<br>text<br>text<br></div>

<div class="one-line">text</div>

<div class="one-line">text<br>text<br>text<br>text<br>text<br>text<br>text<br></div>  

И, наконец, без какого-либо псевдоэлемента и только фона на главном элементе:

 .one-line {
  font-size: 2em;
  width: 200px;
  padding-left:50px;
  min-height: 50px;
  height: auto;
  background: 
   linear-gradient(blue,blue) left/calc(100% - 50px) 100%,
   linear-gradient(to bottom left, transparent 49.4%, red 50%) top right/50px 50.2%, 
   linear-gradient(to top left, transparent 49.4%, red 50%) bottom right/50px 50.2%;
  background-repeat:no-repeat;
  margin: 5px;
  position: relative;
  color: #fff;
}  
 <div class="one-line">text<br>text<br></div>
<div class="one-line">text<br>text<br>text<br></div>

<div class="one-line">text</div>

<div class="one-line">text<br>text<br>text<br>text<br>text<br>text<br>text<br></div>  

Комментарии:

1. спасибо за ответ @Temani, ты всегда помогаешь. Я буду искать совместимость с браузером.

2. добро пожаловать @bhansa 😉 кстати, я думаю, вы обнаружите проблему только с IE, как обычно 🙂

3. @bhansa я добавил другое решение, которое должно быть более поддерживаемым 🙂

Ответ №2:

Ну, вы могли бы сохранить стрелку того же размера и выровнять ее по середине, изменив top на top: 50%; и добавив transform: translateY(-50%);

 .one-line{
  
  width: 150px;
  min-height: 50px;
  height: auto;
  background: blue;
  margin: 5px;
  position: relative;
  color: #fff;
  
}

.one-line:after{
  content: '';
  display: block;
  position: absolute;
  left: 100%;
  width: 0; 
  height: 0; 
  border-top: 25px solid transparent;
  border-bottom: 25px solid transparent;
  border-left: 25px solid red;
  
  top: 50%;
  transform: translateY(-50%);
}  
 <div class="one-line">text<br>text<br>text<br>text</div>

<div class="one-line">text<br>text<br>text<br>text<br>text<br>text<br>text<br>text<br>text<br>text<br>text</div>  

Комментарии:

1. спасибо за ваш ответ, я имею это в виду. Я все еще пытаюсь добиться упомянутого поведения. Хотя только для двух строк текста.

Ответ №3:

используя путь svg в качестве background-image , вы могли бы расширить background-size свойство до 100% 100% . Просто убедитесь, что svg имеет preserveAspectRatio="none"

 .one-line:after {
    background-image: url('data:image/svg xml;charset=UTF-8,<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" preserveAspectRatio="none" viewBox="0 0 25.1 50" style="enable-background:new 0 0 25.1 50;" xml:space="preserve"><polygon class="st0" points="0,50 0,50 25,25 0,0" fill="#ff0000"/></svg>');
    position: absolute;
    top: 0;
    left:100%;
    height: 100%;
   width: 25px;
    background-size: 100% 100%;
    background-repeat:no-repeat;
    display: block;
    content:'';
}
  

https://jsfiddle.net/7jm54u6L/

Комментарии:

1. это должно быть background-repeat вместо повторения. Кстати, отличное решение

2. спасибо, что указали на это. Отредактировал мой ответ с вашим исправлением