Как вставить разрыв строки

Оцените материал
(0 голосов)

Проблема

Необходимость разрывать строки средствами CSS обычно возникает при использовании списков определений, но также в некоторых других случаях. Чаще всего мы используем списки определений, потому что хотим быть добропорядочными кибергражданами и создавать правильную семантическую разметку, даже если визуальный результат, который нам требуется, — это всего лишь несколько строк с парами из имени и значения. Рассмотрим такую разметку:
HTML
<dl>
<dt>Name:</dt>
<dd>Lea Verou</dd>
<dt>Email:</dt>
<dd>Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра.<;/dd>
<dt>Location:</dt>
а<dd>Earth</dd>
</dl>
Ожидаемый визуальный результат — простая стилизация, показанная на рисунке.
На первом шаге мы чаще всего применяем пару простых приемов CSS, например:
dd {
margin: 0;
font-weight: bold;
}
Как вставить разрыв строкиОднако поскольку  <dt> и  <dd> — это блочные элементы, в результате у нас получается нечто более напоминающее рисунок ниже, когда каждое имя и каждое значение отображаются на отдельной строке.

Последующие попытки обычно включают тестирование разных значений свойства  display для элемента  <dt>, <dd> или обоих, вплоть до абсолютно произвольных, по мере того как мы приходим в полное отчаяние. Но результат при этом чаще всего оказывается похожим на рисунок ниже.


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

 

 

Решение

По сути нам нужно только добавить переносы строк в конце каждого  <dd> . Если мы ничего не имеем против презентационной разметки, то можно сделать это с помощью старых добрых элементов  <br> . Скажем, так:
HTML
<!-- Каждый раз, когда вы делаете это, где-то умирает котенок -->
<dt>Name:</dt>
<dd>Lea Verou<br /></dd>
Затем мы применили бы  display:inline; ко всем  <dt> и  <dd> и заявили, что дело сделано. Разумеется, это не только плохая практика с точки зрения поддержки; при использовании данного подхода код несоразмерно раздувается. Если бы мы могли использовать генерируемое содержимое для добавления переносов строки, работающих аналогично элементам  <br> , это сразу решило бы нашу проблему! Но мы этого сделать не можем… Или все же можем? В действительности существует символ Unicode, соответствующий  переносу строки:  0x000A . В CSS-коде мы должны записывать его как  "\000A" или, еще проще,  "\A" . Его можно использовать в качестве содержимого нашего псевдоэлемента  ::after , чтобы он автоматически добавлялся в конце каждого  <dd>, например так:
dd::after {
content: "\A";
}
Вроде бы это должно сработать, но если мы попытаемся применить этот код, результат нас разочарует: по сравнению с рисунком выше ничего не изменится. Но это не означает, что мы идем по неверному пути, просто мы кое-что забыли. На самом деле то, что мы делаем с помощью этого CSS-кода, эквивалентно добавлению переносов строки в нашей HTML-разметке прямо перед закрывающимися тегами  </dd> . Помните, чтопроисходит с переносами строк в коде HTML? По умолчанию они схлопываются вместе с остальным пустым пространством. Чаще всего это как раз то, что нам нужно, так как в противном случае нам пришлось бы форматировать всю HTML-страницу целиком как одну строку. Однако иногда пустое пространство и переносы строки нужно сохранять, как, например, в блоках с примерами кода. И что же мы обычно делаем в таких ситуациях? Мы применяем  white-space: pre; . То же самое можно сделать и в нашем примере, но только для генерируемых переносов строк. Все, что у нас есть, — это один символ переноса строки, поэтому нас не особо волнует, сохранится пустое пространство или нет (оно все равно отсутствует). Следовательно, нам подойдет любое значение  pre (pre ,  pre-line ,  pre-wrap). Я рекомендую использовать  pre , так как оно поддерживается наибольшим количеством браузеров.  Давайте соберем все вместе:
dt, dd { display: inline; }
dd {
margin: 0;
font-weight: bold;
}
dd::after {
content: "\A";
white-space: pre;
}
Протестировав этот код, вы увидите, что он действительно работает и обеспечивает результат. Но насколько это решение гибкое? Предположим, мы хотим добавить второй адрес электронной
почты к записям пользователей, которые содержатся в нашем списке определений:
HTML
...
<dt>Email:</dt>
<dd>lЭтот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра.<;/dd>
<dd>Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра.Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра.;/dd>
...
Технически 0x000A соответствует символу Line Feed(Перевод строки»), которыймы получаем в JavaScript, когда используем "\n". Есть также символ Carriage Return(Возврат каретки», "\r" в JS, "\D" в CSS), но в современных браузерах он нетребуется.

Теперь результат выглядит, как показано на рисунке, и это действительно странно. Поскольку перенос строки добавляется после каждого  <dd> , каждое значение выводится на отдельной строке, даже если необходимости переносить его на новую строку нет. Было бы намного лучше, если бы множественные значения разделялись запятыми, но оставались на одной строке (при условии, что там достаточно места).
В идеальном случае нам хотелось бы выбирать только последние  <dd> перед <dt> и добавлять переносы строк только для них, но не для всех элементов  <dd>. Однако в своем текущем состоянии селекторы CSS не обеспечивают такой точности, потому что не способны заглядывать вперед и проверять элементы после субъекта в DOM-дереве. Необходимо придумать другой способ. Одна из идей — попробовать добавлять переносы строк перед  <dt> , а не после  <dd> :
dt::before {
content: '\A';
white-space: pre;
}
Однако это приводит к появлению пустой первой строки, поскольку селектор применяется также и к первому  <dt> . Для того чтобы справиться с этим, можно попытаться использовать любой из следующих селекторов вместо  dt:
‰ dt:not(:first-child)
‰ dt ~ dt
‰ dd + dt
Мы выберем последний вариант, так как он будет работать, в том числе и в сценарии, когда для одного и того же значения определено несколько элементов <dt> , в отличие от первых двух селекторов, которые в таких условиях ломаются. Также нам необходимо как-то разделять множественные элементы  <dd> , если использование в качестве разделителя обыкновенного пробела нас не удовлетворяет (это допустимо в одних случаях, но дает плохие результаты в других). В идеальной ситуации нам бы хотелось иметь возможность сказать браузеру:
«Добавляй запятую после каждого  <dd> , предшествующего другому  <dd> », но опять же, современные селекторы CSS не настолько хороши. Таким образом, нам придется добавлять запятую перед каждым  <dd> , следующим за другим <dd> . Результирующий CSS-код представлен далее (а результат вы можете увидеть на рисунке):
dd + dt::before {
content: '\A';
white-space: pre;
}
dd + dd::before {
content: ', ';
font-weight: normal;
}

Помните, что если ваша разметка включает (незакомментированное) пустое пространство между множественными последовательными элементами  <dd>, то перед запятой появится пробел. Есть несколько способов справиться с этим недостатком, но ни один из них не идеален. Например, поля отрицательного размера:
dd + dd::before {
content: ', ';
margin-left: -.25em;
font-weight: normal;
}
Это решение будет работать, но оно довольно хрупкое. В случае отображения содержимого на другом фоне и с другими метриками это пространство может оказаться шире или уже  0.25em , и тогда результат будет выглядеть странно. Однако с большинством шрифтов разница пренебрежимо мала.

ПОПРОБУЙТЕ САМИ!
http://play.csssecrets.io/line-breaks

Десерт на сегодня - видео о рефери, которому явно стало скучно

Прочитано 220 раз
Другие материалы в этой категории:
Понравилась запись? Подпишитесь на обновления по почте:

Оставить комментарий

Убедитесь, что вы вводите (*) необходимую информацию, где нужно
HTML-коды запрещены

Поиск по сайту

Google+