Подтвердить что ты не робот

Равномерно распределять элементы с помощью CSS

Сегодня в журнале Smashing Magazine появился метод распределения элементов равномерно в контейнере с использованием CSS .

Недавно мне пришлось использовать Javascript для достижения такого же эффекта для элементов переменной ширины, но метод, представленный на SM, заставил меня задаться вопросом, возможно ли это сделать без Javascript.

Здесь этот вопрос, где gargantaun говорит:

ИМХО, и вы, вероятно, не хотите это слышать, но дизайн, вероятно, испорчен. Общеизвестно, что распределение элементов равномерно по макету с помощью CSS - это боль, поэтому разработчикам следует избегать этого.

Но я не могу сказать дизайнеру изменить его дизайн, и я не согласен с тем, что недостатки CSS должны ограничивать дизайнеров.

В любом случае, вот что я имею в HTML (переведенный и упрощенный):

<div id="menu">
    <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/news">News</a></li>
        <li><a href="/theme">Theme</a></li>
        <li><a href="/activities">Activities</a></li>
        <li><a href="/contact">Contact</a></li>
    </ul>
</div>

в CSS (нерелевантные свойства удалены и упрощены):

#menu li { float: left; margin-right: 20px; }
#menu a  { display: block; padding: 0 1em; }

и в Javascript:

function justifyMenu() {
    var menuItems  = $$("#menu li");
    var menuWidth  = $("menu").getWidth();
    var totalWidth = 0;

    menuItems.each(function(e) {
        totalWidth += e.getWidth();
    });

    var margin = (menuWidth - 4 - totalWidth) / (menuItems.length - 1);
    margin = parseInt(margin);

    menuItems.each(function(e) {
        e.setStyle({ marginRight: margin + 'px' });
    });

    menuItems[menuItems.length - 1].setStyle({ marginRight: '0' });
}

И здесь уменьшенный снимок экрана (см., как меню выравнивается с изображением заголовка):

снимок экрана http://i41.tinypic.com/2ntguf8.png

Любая идея, как я могу добиться этого без Javascript?

4b9b3361

Ответ 1

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

Независимо от причин, по которым вы могли бы отказаться от таблиц, это не может быть хуже, чем в зависимости от Javascript для компоновки вашей страницы.

Да, я знаю, что это не тот ответ, который вы искали, но golly, это так очевидно.

Ответ 2

Были случайные утверждения о том, что таблицы являются очевидным решением, однако не было реального обсуждения того, как его реализовать. Я покажу вам, что отображение divs как таблицы является правильным способом для этого, но это не так просто, как центрирование всех ячеек и установка автоматической ширины. Проблема заключается в том, что вы не контролируете внешние поля более-менее левого и правого содержимого ячеек. Они оба вставляют из своей коробки с ящиком произвольную сумму, которую вы не можете контролировать. Вот работа вокруг:

Во-первых, небольшая модификация Guder html:

<div id="menu">
    <ul>
        <li class="left"><a href="/">Home</a></li>
        <li><a href="/news">News</a></li>
        <li><a href="/theme">Theme</a></li>
        <li><a href="/activities">Activities</a></li>
        <li><a href="/contact">Contact</a></li>
    </ul>
</div>

Теперь css:

#menu {display:table; width:// some width in px //}
#menu ul {display:table-row; width: 100%}
#menu li.left {display: table-cell; text-align: left; width: 20px; white-space:nowrap;}
#menu li {display: table-cell; text-align: right; width: auto;}

Теперь мы имеем полный контроль над внешними сторонами меню, которые выравниваются с крайними левыми и крайними правыми сторонами содержащего окна, а расстояние между каждым элементом согласовано. Вы заметите, что я использовал трюк, чтобы получить самую дальнюю левую ячейку, чтобы быть точной шириной ее содержимого. Я установил свойство width для небольшого размера, явно ниже того, что обычно будет в его содержимом. Затем я устанавливаю пустое пространство в no-wrap, которое растягивает ячейку как минимум, чтобы соответствовать тексту ячейки. Здесь вы можете увидеть изображение, которое показывает эффект этого (используя разные элементы html):

riffing on cats

Красота этого кода заключается в том, что он может принимать любое количество ячеек и ширины текста без каких-либо знаний об их фактической ширине и равномерно распределять их по всей странице. Все это время левые и правые элементы достигают своих периметров, и, конечно, у нас есть все наши html в divs, ни один браузер или интернет-разработчик не ошибается, полагая, что мы представляем табличные данные. Никаких известных компромиссов здесь!

Ответ 3

Это то, что отображает: table-cell должно быть достигнуто - однако IE просто этого не делает, и FF < 3 также имеет проблемы с этим.

Эти стили работают в FF3, Chrome, Safari и (я думаю) Opera 9:

#menu ul {display:table;padding:0;}
#menu li {display:table-cell;text-align:center;}

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

Ответ 4

Несмотря на то, что ответ Колина Брогана обеспечивает прочную основу для решения проблемы "почти там", проблема все равно зависит от длины текста. Если текст слишком длинный, "ячейка" будет шире и, следовательно, больше места слева. Я попытался решить проблему на основе кода, представленного в его ответе, но я пришел к выводу, что проблема не имеет реального возможного решения с таблицами или поддельными таблицами (display: table-cell).

Таким образом, нам придется ждать, когда более гибкая модель ячеек CSS3 будет поддерживаться (вы можете проверить обновленную поддержку здесь). Тем временем вы можете использовать Flexie polyfill для исправления браузеров, которые его не поддерживают. Если вы хотите проверить, как это будет выглядеть в WebKit сейчас (без необходимости polyfill), вы можете попробовать следующий CSS:

#menu ul {
  display: -webkit-box;
  -webkit-box-orient: horizontal;
  -webkit-box-pack: justify;
  width: 940px;
  list-style: none;
  padding: 0;
  border: 1px solid gray;
}
#menu li {
  border: 1px solid silver;
}

Обратите внимание, что он использует только префиксы WebKit. Вы должны добавить префиксы для других браузеров, а также, если вы решите перейти на веб-сайт.

Этот подход принимает неизвестное количество элементов и ширину текста без каких-либо знаний об их фактической ширине и равномерно распределяет их по их контейнеру (в этом случае #menu ul).

Если вы решите быть консервативным, подход, предложенный Колином Броганом, является наиболее приемлемым, если вы держите свои тексты на одной и той же приблизительно длине. Если нет, откроются более широкие пробелы.

Ответ 5

Да, вы можете это сделать, если ширина распределяемых элементов заранее известна. Но это немного грязно.

Фокус в том, что вам нужно расстояние между каждым элементом "(Wp-sum (Wc))/(Nc-1), то есть ширина родительского элемента минус общая ширина всех дочерних элементов, разделенная поровну между количеством промежутков между элементами.

Поскольку CSS не имеет возможности делать выражения, нам нужно немного взломать его. Сначала мы добавляем маркер к родительскому элементу размера sum (Wc), общей ширины всех дочерних элементов. Итак, теперь родитель имеет ширину '(Wp-sum (Wc)), и мы можем использовать значение дополнения в% относительно этой ширины.

Так, например, для четырех изображений размером 10px, 20px, 40px и 80px соответственно наша сумма (Wc) равна 150px. Установите это как родительское поле, тогда дети могут иметь одну треть этой ширины в качестве дополнения между ними.

<style type="text/css">
    #nava { width: 10px; height: 20px;}
    #navb { width: 20px; height: 20px;}
    #navc { width: 40px; height: 20px;}
    #navd { width: 80px; height: 20px;}

    #nav { margin-right: 150px; white-space: nowrap; }
    #nava, #navb, #navc { padding-right: 33.3%; }
</style>

<div id="nav"
    ><img id="nava" src="nava.png" alt="a"
    ><img id="navb" src="navb.png" alt="b"
    ><img id="navc" src="navc.png" alt="c"
    ><img id="navd" src="navd.png" alt="d"
></div>

Смешной отступ тегов заключается в том, чтобы избежать пробелов между изображениями. 'Nowrap необходим, потому что с шириной родительского набора, уже шириной страницы, в противном случае было бы невозможно поместить все элементы в строку. Наконец, в IE вам может понадобиться добавить обертку div вокруг партии с "width: 100%; overflow: скрытый, чтобы предотвратить нежелательные полосы прокрутки, если вы охватываете всю страницу. И, конечно же, вы захотите быть в стандартном режиме.

Это также может работать с текстовыми элементами, если вы делаете их встроенными блоками, чтобы добавить дополнение, и вы произвольно задаете их в ems. Он не будет работать, если размеры дочерних элементов неизвестны заранее (например, они содержат динамический контент), так как вы не будете знать значение суммы (Wc) для использования.

Честно говоря, я бы просто использовал таблицу. Алгоритм компоновки таблиц очень плавно справляется с расчетом распределения ширины запасной таблицы. (Используйте "table-layout": исправлены для получения наилучших результатов с ячейками известной ширины или "автоматически реагировать на динамическое содержимое".) Таким образом, вам также не нужно беспокоиться об ошибках округления пикселей.

Ответ 6

Если вы использовали текстовые размеры (em, ex), это было бы намного проще. Затем вы можете обрабатывать буквы, а не пиксели.

Пример: все дело в 30 заглавных букв Ms wide. Затем вы можете использовать ширину каждого навигационного элемента (на основе его текстового содержимого) и делать свою математическую статистику там.

Ответ 7

Вот код в формате jQuery для тех, кто считает его полезным

function justifyClients() {
                        var menuItems  = $("#clients-wrapper ul li").get();                         
                        var menuWidth  = $("#clients-wrapper ul").width();                          
                        var totalWidth = 0;

                        $("#clients-wrapper ul li").each(function(i,e)
                                        {
                                            totalWidth += $(e).width();
                                        });

                        var margin = (menuWidth - 4 - totalWidth) / ($("#clients-wrapper ul li").length - 1);
                        margin = parseInt(margin);

                        $("#clients-wrapper ul li").each(function(i,e) {

                            if(i < $("#clients-wrapper ul li").length - 1)
                            {
                                alert(i + " " + $("#clients-wrapper ul li").length);
                                $(e).css('margin-right',  margin);
                            }
                        });
                    }

                    $(document).ready(function() {
                      justifyClients();
                    });

Ответ 8

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

Этот метод работал у меня. Идея состоит в том, чтобы создать содержащийся элемент text-align: justify и заставить элементы распространять отображение: inline-block.

HTML:

<div id="menu">
    <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/news">News</a></li>
        <li><a href="/theme">Theme</a></li>
        <li><a href="/activities">Activities</a></li>
        <li><a href="/contact">Contact</a></li>
        <li class="filler"></li>
    </ul>
</div>

CSS

#menu {
    text-align: justify;
}

ul {
    margin: 0;
    padding: 0;
}

#menu li {
    display: inline-block;
}

.filler {
    width: 100%;
    height: 0;
}

Ответ 9

AFAIK нет способа добиться этого только с помощью CSS. Кто-нибудь исправит меня, если это не так, PLS.

Ответ 10

Если вы используете Yahoo! Библиотека пользовательского интерфейса (YUI) grids.css, это может сработать.

Ответ 11

Демо - http://codepen.io/vsync/pen/tFwxu

все, что вам нужно, если сделать сам список text-align:justify, а затем добавить некоторый псевдо-элемент в конец его и сделать его заполнением всей ширины, чтобы обмануть список, чтобы оправдать все его элементы по всей ширине.

Ответ 12

Тревор Диксон улучшенный вариант (без дополнительных <li>)

HTML

<ul>
    <li><a href="/">Home</a></li>
    <li><a href="/news">News</a></li>
    <li><a href="/theme">Theme</a></li>
    <li><a href="/activities">Activities</a></li>
    <li><a href="/contact">Contact</a></li>
</ul>

CSS

ul {
    margin: 0;
    padding: 0;
}
ul li {
    display: inline-block;
    text-align: justify;
}
ul:after{
    display: inline-block;
    content: '';
    width: 100%;
    height: 0;
}

Ответ 13

Благодаря CSS3 Flexbox module это возможно с двумя строками CSS.

Проверьте Таблица совместимости браузера для Flexbox

HTML

<div id="menu">
  <ul>
    <li><a href="/">Home</a>
    </li>
    <li><a href="/news">News</a>
    </li>
    <li><a href="/theme">Theme</a>
    </li>
    <li><a href="/activities">Activities</a>
    </li>
    <li><a href="/contact">Contact</a>
    </li>
  </ul>
</div>

CSS

ul {
  display: flex;
}
li {
  flex: 1; /* Short hand for flex-grow: 1 and flex-shrink: 1 */
}

Вывод:

ul, li {
  margin: 0;
  padding: 0;
}
ul {
  display: flex;
  list-style: none;
}
li {
  flex: 1;
  text-align: center;
}
<div id="menu">
  <ul>
    <li><a href="/">Home</a>
    </li>
    <li><a href="/news">News</a>
    </li>
    <li><a href="/theme">Theme</a>
    </li>
    <li><a href="/activities">Activities</a>
    </li>
    <li><a href="/contact">Contact</a>
    </li>
  </ul>
</div>