3

Я использую стилизованные HR для создания разделителей секций.
Но теперь я пытаюсь создать элемент H1 с нижней границей меньше ширины H1 (переменная ширина в соответствии с шириной текста H1) и с более толстой чертой в середине (высотой).

Что-то вроде этого:

введите сюда описание изображения

Я просмотрел несколько поисковых источников, пытаясь найти решение, но не нашел ничего похожего.

Я пытался использовать: after и: before, но все равно застрял. Есть идеи?

Вот что я пробовал до сих пор:

h1 {
  display:inline;
  border-bottom:1px solid black;
}

h1:after { content: ''; display: block; width: 100%; height: 100%; border-bottom:3px solid red; }

<h1>
My Text
</h1>

Свободный перевод вопроса Create border-bottom smaller than element and with thicker middle от участника @Russel Riehle.

Alexandr_TT
  • 110,146
  • 23
  • 114
  • 384
  • 1
    ассоциация:https://stackoverflow.com/q/50051607/7394871 – Alexandr_TT Jul 30 '21 at 12:11
  • 1
    Похожая задача (тут линия ступенчатой толщины нужна под текстом, а там - по бокам от него): Как сделать боковые линии от текста в css?. – yar85 Jul 30 '21 at 16:05
  • @yar85 таких вопросов, ответов с линиями под, около текста много и у нас и на Enso/ Это решение показалось мне интересным и полезным, поэтому и перевёл – Alexandr_TT Jul 30 '21 at 16:12
  • @yar85 вы можете, при желании, дать свой вариант решения этого вопроса. Галочка и плюс гарантирован при качественном ответе – Alexandr_TT Jul 30 '21 at 16:15
  • Вариант решения в уже написанном ответе, по сути использует тот же подход что в связанном вопросе, и тут вряд ли получится придумать что-то новое :) Использование линейного градиента в фоновой картинке - это хорошее, и самое оптимальное (имхо) решение из тех что возможны без помощи SVG (в которой я не очень разбираюсь, но она вроде позволяет сделать ступенчатую векторную линию которая будет растягиваться только "хвостиком": что-то вроде такого, но с линией). – yar85 Jul 30 '21 at 16:25
  • @yar85 добавил метки, чтобы стали возможны другие решения. На мой взгляд, чем больше решений, тем лучше – Alexandr_TT Jul 30 '21 at 16:28
  • @Alexandr_TT, а где метка canvas?))) Так не интересно. – Leonid Jul 30 '21 at 17:01
  • @Leonid добавил метку, жду ответа :) – Alexandr_TT Jul 30 '21 at 17:06

5 Answers5

3

Вы можете легко сделать это с помощью linear-gradient без дополнительной разметки или псевдоэлемента:

h1 {
  display:inline-block;
  font-size:3em;
  padding-bottom:10px;
  background:
   linear-gradient(red 0 0) 50% calc(100% - 2px)/80% 2px,
   linear-gradient(red 0 0) 50% 100%            /40% 6px;
  background-repeat:no-repeat;
}
<h1>Lorem Ipsum</h1>

Свободный перевод ответа от участника @Temani Afif.

Alexandr_TT
  • 110,146
  • 23
  • 114
  • 384
3

Вариант с псевдоэлементами

h1 {
  display: inline-block;
  position: relative;
}

h1::before{ content: ''; position: absolute; bottom: 2px; left: 50%; width: calc(100% - 2rem); height: 1px; background-color: red; transform: translateX(-50%); }

h1::after { content: ''; display: block; width: 50px; height: 100%; margin: 0 auto; border-bottom: 5px solid red; }

<h1>My Text</h1>
<br>
<h1>My Text Text Text Text Text Text Text Text</h1>
soledar10
  • 27,573
3

С использованием SVG (насколько хватает моих скудных познаний в данной технологии):

h1 {
  width: fit-content;
  margin: 0.5em auto;
  font: bold 3rem sans-serif;
}

.test { display: block; width: 50%; height: 3px; margin: 0.1em auto 0; transition: 0.3s ease; }

.test .line { stroke: red; fill: red; transition: inherit; }

#grow:checked ~ h1 .test { width: 100%; } #proportions:checked ~ h1 .test .line.thick { transform: scaleX(0.25); } #thickness:checked ~ h1 .test { height: 6px; }

<input id="grow" type="checkbox"><label for="grow">Увеличить ширину</label><br>
<input id="proportions" type="checkbox"><label for="proportions">Изменить пропорции сегментов</label><br>
<input id="thickness" type="checkbox"><label for="thickness">Повысить толщину</label><br>

<h1>Lorem Ipsum
  <svg class="test" viewBox="0 0 100 3" preserveAspectRatio="none">
    <line class="line thin" x1="0" y1="50%" x2="100" y2="50%" stroke="black" stroke-width="1px" />
    <rect class="line thick" width="100%" height="100%" transform="scale(0.5 1)" transform-origin="center" />
  </svg>
</h1>

Больше всего трудностей - с центровкой элемента rect'а (толстая часть линии) при сохранении возможности изменять его ширину.
При том что transform в SVG не работает с процентами (что похоже исключает динамическую центровку, а значит и задание ширины в абс. единицах таких как px), получилось сделать изменение размера толстого сегмента только относительно, через scale: т.е. в диапазоне 0..1, где 1 это полная ширина всей линии.

yar85
  • 10,940
  • width: fit-content; - экспериментальная штука из CSS4 (только эвергрин браузеры, глобал покрытие 91.14% без префиксов)... минздрав предупреждает, IE плачет, и т.д.. – yar85 Jul 30 '21 at 19:59
  • 1
    очень интересный и познавательный ответ, по крайней мере для меня. Из серии... А разве так можно было :))) тут и сочетание модели objectBoundingBox и viewBox="0 0 100 3" preserveAspectRatio="none" то есть растягивание без соблюдения пропорций и scaleX -css Просто гремучий замес. Великолепно, буду изучать, экспериментировать. Появилось много свежих мыслей. Я бы ответил намного стандартней и скучнее :))) Вот она свежая кровь, обязательно отвечайте и дальше на вопросы SVG/ Спасибо за ответ! – Alexandr_TT Jul 30 '21 at 20:26
  • 1
    @Alexandr_TT, честно признаюсь, сначала я делал с соблюдением пропорций (пытаясь использовать отличные от none значения preserveAspectRatio на вложенных <svg> с применением use атрибута и разных вьюбоксов) - но ничего не получалось, и окончательно психанув (типа "ох уж этот глупый SVG, надоел"), все стер и сделал наиболее примитивным способом :D технология-то мощная, но какая-то она недружественная к новичкам. Враждебная даже)) Еще смущает отсутствие инструментов отладки SVG в devtools браузера, аналогичных тем что мы имеем для HTML+CSS... если в будущем добавят, учиться будет проще. – yar85 Jul 30 '21 at 20:36
  • 1
    очень много моих друзей программистов (довольно сильных и высокооплачиваемых) сломались на SVG :) поэкспериментировав неделю, две методом тыка, заканчивали одинаково - да пошёл этот SVG. Хотя в этом языке всё логично и математически точно. Его беда в том, что его никто не поддерживает настоящим образом, 25 лет ничего не делается Как начал его топить мелкософт продвигая свой платный VML, так и сейчас продолжается, но уже по другому. И несмотря на это не могут выбросить SVG на свалку. Он до сих пор мощнее и гибче CSS, Canvas в анимации, фильтрах и т.д – Alexandr_TT Jul 30 '21 at 20:58
2

Решение с помощью псевдоэлемента и background-image:

h1 {
  display: inline-block;
}

h1:after { content: ''; display: block; background-image: url("data:image/gif;base64,R0lGODlhCgAFAJEAAP8AAP///wAAAAAAACH5BAkAAAEALAAAAAAKAAUAAAgYAAMIBEAQgMCDAQoaHKiw4UGFCBkSPBgQAA=="); background-repeat: no-repeat; background-size: 100% 5px; height: 5px; image-rendering: pixelated; margin-top: 0.5em; margin-left: 20%; margin-right: 20%; }

<h1>Very small!</h1><br>
<h1>This is small header!</h1><br>
<h1>This very very very long header!</h1>

Проблемы все те же + изображение настраивать. Отступы можно задавать при помощи margin-left, margin-right.

  • может добавите в заголовок вместо Для разнообразия: --- Решение с помощью псевдоэлемента и background-image – Alexandr_TT Jul 31 '21 at 07:20
1

Нельзя назвать данный ответ правильным, но попытка использовать canvas для этой задачи. Заметьте, что свойства h1 меняются только на время вычисления истинной ширины текста, затем возвращается все на место. H1 сохраняет свойство display:block, а также текст расположен по центру. При этом подчеркивание только на ширину самого текста.

Для того, чтобы поведение canvas было "естественным", добавляю свойство display:inline. Так он будет отцентрирован как и остальной текст, но требуется искусственный перенос на следующую строку. И эту проблему я смог решить только с помощью добавления тега <br>. И вот никак не могу уменьшить его высоту чтобы подчеркивание прижалось к тексту.

const LINE_COLOR = '#ea596e';

let h1 = document.querySelector('h1');

let canvas = document.querySelector('canvas');

canvas.width = 0; canvas.height = 0;

let display = window.getComputedStyle(h1).getPropertyValue("display"); let align = window.getComputedStyle(h1).getPropertyValue("text-align");

h1.style.textAlign = 'left'; h1.style.display = 'inline-block';

let rect = h1.getBoundingClientRect();

h1.style.textAlign = align; h1.style.display = display;

let w = canvas.width = rect.width; let h = canvas.height = 5;

let ctx = canvas.getContext('2d');

ctx.fillStyle = LINE_COLOR; ctx.fillRect(20,2,w-40,1); ctx.fillRect(w/4,0,w/2,h);

<h1 style="text-align:center">What an awsome solution!
    <br>
    <canvas style="display:inline"></canvas>
</h1>

Добавляю и "улучшенный" вариант с текстом, заключенным в span. Вместо br использую div с отрицательным margin-top. Теперь не надо играть свойствами h1 чтобы получить ширину текста. Код проще.

Свойство display:inline для canvas, похоже смысла не имело, убираю лишнее.

const LINE_COLOR = '#ea596e';

let h1_span = document.querySelector('h1 > span');

let canvas = document.querySelector('canvas');

let w = canvas.width = h1_span.getBoundingClientRect().width; let h = canvas.height = 5;

let ctx = canvas.getContext('2d');

ctx.fillStyle = LINE_COLOR; ctx.fillRect(w/8,2,w-w/4,1); ctx.fillRect(w/4,0,w/2,h);

<h1 style="text-align:center">
    <span>What an awsome solution!</span>
    <div style="margin-top: -16px"></div>
    <canvas></canvas>
</h1>
Leonid
  • 5,797
  • на коротких фразах работает чудесно. Проблемы с переносом действительно появляются на длинных фразах в заголовке – Alexandr_TT Jul 30 '21 at 18:35
  • Тогда подчеркивание растягивается на всю ширину, а как должно быть иначе? При уменьшении экрана ничего не пересчитывается. Я тоже мог загнать текс в span и сильно упростить код)) Пропусти фразу "меньше ширины" немного изменил код. – Leonid Jul 30 '21 at 18:40
  • в вопросе присутствует некоторая неопределенность. Непонятно насколько должно быть меньше подчеркивание длины фразы заголовка, насколько должна быть меньше толстая, короткая линия по сравнению с общей длиной. Поэтому, что имеем, то имеем. – Alexandr_TT Jul 30 '21 at 18:51
  • @Alexandr_TT, настаиваю на переопределении принятого ответа. У меня то глупость на тему. Кто же знал, что будет столько интересных ответов)) – Leonid Jul 31 '21 at 16:51
  • твой ответ был первым и вполне качественным. Плюс у меня принцип, если я принял решение, то потом не меняю его. – Alexandr_TT Jul 31 '21 at 17:05