Резиновое меню
Дата публикации: 13.01.2011
Задача
Сделать резиновое меню, которое занимает всю доступную ширину родителя. При этом первый пункт располагается у левого края, последний — у правого и расстояния между пунктами одинаковые.
Требования
- все пункты должны быть в одну строку;
- универсальность: число пунктов и длина текста в каждом за ранее не известна, количество слов в пункте может быть разным;
- семантический код: меню должно быть обычным списком;
- без использования javascript.
Проблема
Задача казалось бы несложная, но для ее решения обычно применяется таблица или javascript. Проэмулировать для этой задачи таблицу с помощью display: table/table-cell не выходит, по крайней мере кроссбраузерно. Вот и имеем 21 век на дворе, HTML5, CSS3, а такое меню реализовываем «костылями». Но решение все-таки нашлось.
Решение
Основная фишка — это применение свойства text-align: justify, которое позволяет растянуть текст на всю ширину родителя. Одна важная особенность — такое выравнивание сработает, если текста будет больше, чем на одну строку. Вторая особенность — слова будут растягиваться независимо от того в разных они пунктах или в одном. Но все в принципе решаемо:
<ul> <li><a href="#">Главная</a></li> <li><a href="#">Собираем</a></li> <li><a href="#">Следим</a></li> <li><a href="#">Без цензуры</a></li> <li><a href="#">Учимся</a></li> <li><a href="#">Справочники</a></li> </ul>
ul { text-align: justify; overflow: hidden; /* нужно чтобы обрезать разные побочные эффекты приема */ height: 20px; /* нужна чтобы устранить один побочный эффект, но иногда можно обойтись без нее */ cursor: default; /* растянутый текст justify приведет к тому что почти вся плашка меню будет иметь cursor: text */ margin: 50px 100px 0 100px; background: #CCCCCC; padding: 5px; } li { display: inline; /* чтобы пункты меню выступали в роли текста */ } li a { display: inline-block; /* чтобы не разрывались слова в пунктах меню */ color: #0000CC; } a:hover { color: #ff0000; } ul:after { /* эмуляция дополнительной строки, чтобы сработал justify */ content: "1"; margin-left: 100%; height: 1px; overflow: hidden; display: inline-block; }
Для IE6 и 7 потребуется дополнительный код:
ul { z-index: expression(runtimeStyle.zIndex = 1, insertAdjacentHTML('beforeEnd&apos, '<li class="last"></li>')); } ul .last { margin-left: 100%; } * html ul { /* need ie6 only */ height: 30px; }
Демо пример. Проверено в:
- IE 6-8
- Firefox 3.6
- Opera 10.5
- Safari 5
- Chrome 6
Недостатки
- «раздутый» CSS-код;
- не получится сделать по обычному активный пункт меню (<li class=»active»>текущий пункт</li>) из-за того, что теперь слова в пункте будут разрываться (если, конечно, слов в пункте больше, чем одно). Решить можно добавлением тега, обрамляющего текст, с правилами аналогичными ссылке. Например так: <li class=»active»><span>текущий пункт</span></li>;
- из-за overflow могут быть проблемы, если понадобится выпадающие подменю — придется код под такую задачу подгонять.