От автора: Flexbox оказывается крайне полезным инструментом при проектировании макетов в веб-дизайне. Тем не менее, в некоторых случаях он плохо подходит для вертикального выравнивания текста в блоке. Вернемся к примеру, который я разбирал на прошлой неделе. Тот метод работает, если текст в обеих ссылках одной длины. Если же одну ссылку обернуть в тег, а другую нет, то выравнивание уже не работает.
Не самая страшная проблема, но она раздражает, и я хотел бы ее решить. Для ее решения нам нужно немного JavaScript. Но сперва разметка:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<div id="prevnext" class="flex apart"> <a class="prev-one flex" href="/1059/Responsive-Image-Hinting-Using-the-w-Descriptor" rel="prev" accesskey=","> <span class="thumb"> <img src="toubana-diver.jpg" alt srcset="toubana-diver-2x.jpg 2x"> </span> <span class="articlename"> Responsive Image Hinting: Using w </span> </a> <a class="next-one flex" href="/1063/Techniques-and-Treatments-for-Background-Retina-Images" rel="next" accesskey="."> <span class="articlename"> Techniques and Treatments for Background Retina Images </span> <span class="thumb"> <img src="birds-on-wire.png" alt srcset="birds-on-wire-2x.png 2x"> </span> </a> </div> |
CSS код как и в предыдущей статье.
JavaScript
Предположу, что такой тип навигации появляется на странице один раз. Если это так, то я могу определить каждый элемент меню отдельно при помощи querySelector:
1 2 |
var leftText = document.querySelector("#prevnext a span.articlename"), rightText = document.querySelector("#prevnext a:last-child span.articlename"); |
Все манипуляции с текстовыми ссылками происходят в функции matchHeight():
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function matchHeight() { var difference = leftText.offsetHeight - rightText.offsetHeight; if (difference > 0) { rightText.style.marginTop = "-" + difference+"px"; } if (difference < 0) { leftText.style.marginTop = difference +"px"; } if (difference == 0 && (leftText.hasAttribute("style") || rightText.hasAttribute("style"))) { leftText.removeAttribute("style"); rightText.removeAttribute("style"); } } |
Что делает функция:
Difference измеряет разницу высот между двумя текстовыми ссылками. Значение может быть 0 (ссылки на одной высоте), положительным (левая ссылка выше правой) и отрицательным (т.е. правая ссылка выше левой).
В первом условии мы поднимаем правую ссылку на значение difference (при помощи отрицательного top-margin).
Во втором условии поднимается уже левая ссылка на величину разности высот.
В последнем условии переменная difference может принять значение 0 в случае, если обе ссылки были изначально одной высоты, или они уже были настроены (одну из них приподняли). Также я добавил проверку на встроенные стили в ссылках. Если в ссылках присутствует атрибут style, он удаляется, а обе ссылки вертикально выравниваются.
Функция вызывается после загрузки страницы:
1 |
matchHeight(); |
Скрипт нужно вызывать каждый раз, когда текстовая ссылка оборачивается в блок-обертку (изменяется высота элемента). Было бы здорово добавить здесь обработчик события, однако JS еще не умеет определять изменения в высоте элементов. Можно было бы использовать события по свойству transition, как это сделал Дэвид Уолш, но браузеры пока что тоже не понимают такой функционал, по крайней мере, во flexbox элементах. Вместо этого я вызываю функцию при изменении размера окна при помощи requestAnimationFrame:
1 2 3 |
window.addEventListener("resize", function() { window.requestAnimationFrame(matchHeight); }); |
Задержка в макете
В Chrome я столкнулся с одной интересной проблемой: браузер выравнивает текст при первой загрузке страницы. Если же повторно обновить страницу, ничего не работает. Браузер показывает, что элементы имеют одинаковую высоту, даже если это не так. Я подозреваю, что это связано с ошибками макетирования в браузере. Как я понял, Chrome задает элементам одинаковую высоту при первом рендеринге их на странице после обновления, а через некоторое время немножко исправляет макет.
Решение оказалось не из простых: setTimeout не сработал, как я от него ожидал, то же самое можно сказать и за обработчик события для DOMContentLoaded. Сработало только событие load на JQuery объекте window:
1 2 3 |
$(window).bind("load", function() { matchHeight(); }); |
Источник: //thenewcode.com/
Редакция: Команда webformyself.