Можно ли произвольно складывать неограниченные divs влево или вправо без оболочки?

Я думал, что это будет (относительно) легко, но из ответов это кажется труднее, чем я ожидал.

Возможно, даже невозможно!

ЗАДАЧА

Я хотел бы иметь большой список элементов div, которым можно условно присвоить класс .left или .right.

Все div .left должны располагаться под друг другом слева, а div .right должны располагаться под друг другом с правой стороны. Число div в каждом классе произвольно.

enter image description here

ТРИ УСЛОВИЯ

  • Высота каждого div заранее не будет известна

  • Я бы хотел, чтобы они складывались под друг другом side, независимо от того, сколько divs присутствует, в каком порядке они появляются и сколько назначается на обе стороны.

  • Я не хочу использовать div 'wrapper', как некоторые предложили. Это потому что решение должно обслуживать случайное количество и порядок .left и .right divs (см. пример ниже).

В идеале я хотел бы, чтобы это было чистое решение html/css, как можно более совместимое с обратной связью - хотя я понимаю, что это может оказаться нереалистичным.

ОБРАЗЕЦ HTML

<div class="left">left one</div>
<div class="left">left two</div>
<div class="right">right one</div>
<div class="left">left three</div>
<div class="right">right two</div>
<div class="right">right three</div>
<div class="left">left four</div>
<div class="right">right four</div>
<div class="right">right five</div>
<div class="left">left five</div>
<div class="right">right six</div>
<div class="right">right seven</div>

UPDATE

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

Следовательно, я занимаю четверть своей скудной репутации, пытаясь получить прочное решение!

ОБНОВЛЕНИЕ 2

Кажется, моя первоначальная цель отменена. Поэтому я не отмечен ни как ответ, хотя, приложив щедрость, я присудил его Джошу, который дал мне лучший способ (почти) достижения этого, наряду с большими объяснениями css, которые он использовал.

Спасибо всем за вашу помощь и идеи.

Ответ 1

Вот что я бы рекомендовал:

Fiddle, не требующий хаков

Здесь ключевой CSS, который мы включаем:

@media (min-width:400px){
    .left {
        width: 60%;
    }
    .right {
        width: 30%;
        float: none;
        margin-left: 100%;
        transform: translateX(-100%);
    }
}

Объяснение этого CSS

Что это делает, толкает ваши элементы .right полностью из контейнера влево, а затем перетаскивает их всю ширину.

position: relative; и left: 100%; сообщают элементу, что он должен отображать правый край контейнера.

Затем transform: translateX(-100%); сообщает элементу, что он должен отображать влево (следовательно, отрицательный) 100% его ширины, - который перетаскивает его, чтобы быть на одном уровне с вашим правым краем.

С помощью этого решения элементы могут быть переупорядочены произвольно и никаких дополнительных вычислений не требуется.

Надеюсь, это поможет!

Update:

Fiddle, требующий одного взлома, не зависящего от порядка DOM

Здесь мы изменили:

CSS

.right {
        width: 30%;
        float: none;
        margin-left: 100%;
        transform: translateX(-100%);
        margin-bottom: -1.2rem; /* New */
        margin-top: calc(1.2rem + 5px); /* New */
    }
    .right:first-of-type {
        margin-top: 0;    /*optional - if there a preceding element on the page this will prevent it from being shifted downward*/
    }

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

calc(1.2rem + 5px) для margin-top в основном говорит: добавьте это margin-bottom, которое мы отняли, плюс исходный запас 5px, который у нас был раньше.

Я использую rem единицы здесь, потому что у вас нет определенных размеров шрифта. Как правило, вы хотели бы использовать em, и мы могли бы иметь здесь. Я выбрал 1.2 как значение по умолчанию line-height для этих элементов. Тогда это исправление будет работать только для одной строки текста в элементе. Вам нужно будет осознать высоту отображаемого элемента, чтобы это работало.

Надеюсь, что это поможет!

Обновить, второй

Скрипт с минимальным JavaScript

Сначала добавьте следующее:

CSS

.right.last {
    margin-top: 0;
}

Затем добавьте следующее:

JavaScript

var rights = document.querySelectorAll(".right");
rights[rights.length-1].className += " last";

И вы больше не увидите этот пробел в последнем элементе.

Ответ 2

Я добавляю еще один ответ. Я не хочу испортить предыдущий ответ. Однако с этим ответом устраняется необходимость обертывания div.

JSFiddle здесь

 <div class="left">left one</div>
 <div class="left">left two</div>
<div class="right">right one</div>
<div class="left">left three</div>
 <div class="right">right two</div>
 <div class="right">right three</div>
 <div class="right">right four</div>
 <div class="right">right five</div>

Добавлены свойства float:left;clear : left и float:right;clear:right css

.left {float:left; background: coral; margin-bottom: 5px;}
.right {float:right; background: mediumaquamarine; margin-bottom: 5px;}

@media (max-width:400px){
    .left, .right  {
        width:100%;
    }
}
@media (min-width:400px){
    .left {
        float: left;
    clear : left;
    }
    .right {
        float: right;
        display: inline-block;
        margin-left: 10%;
    clear : right;
    }
}

Ответ 3

Поместите все левые элементы в отдельный div. Также правые элементы внутри отдельного div.

Затем создайте css-стиль, как я сделал в ниже фрагменте кода.
Оно работает! Надеюсь, это то, что вам нужно!

.left {float:left; background: coral; margin-bottom: 5px;}
.right {float:right; background: mediumaquamarine; margin-bottom: 5px;}
.left-wrapper{ float:left; width:60%;}
.right-wrapper{ float:right; width:30%;}

@media (max-width:400px){
    .left, .right, .left-wrapper, .right-wrapper  {
        width:100%;
    }
}
@media (min-width:400px){
    .left {
        width: 100%;
    }
    .right {
        width: 100%;
        float: none;
        display: inline-block;
        margin-left: 10%;
    }
}
<div class="left-wrapper">
<div class="left">left one</div>
<div class="left">left two</div>
<div class="left">left three</div>
</div>
<div class="right-wrapper">
<div class="right">right one</div>
<div class="right">right two</div>
<div class="right">right three</div>
<div class="right">right four</div>
<div class="right">right five</div>
</div>

Ответ 4

Если вы можете определить высоту первых нескольких элементов с левой стороны (при условии, что она начинается с левой стороны) перед правой стороной, тогда это будет возможно: http://jsfiddle.net/n467un0c/29/

.left { 
    float:none; 
    background: coral; 
    margin-bottom: 5px;
}

.right { 
    float:right; 
    background: mediumaquamarine; 
    margin-bottom: 5px;
    position: relative;
    top: -46px; /** this value should be the height of the elements added together (including the margins) on the left side BEFORE the first element on the right side... in this case it would be 'left one' and 'left two' before 'right one' **/
}

@media (max-width:400px){
    .left, .right  {
        width:100%;
    }
}
@media (min-width:400px){
    .left {
        width: 60%;
        margin-right: 10%;
    }
    .right {
        width: 30%;
        clear: right;
    }

Ответ 5

Я обновил JSFiddle здесь. Он работает сейчас. Я добавил дополнительные обертки в левые div и правые div.

<div class="left">
 <div class="left">left one</div>
 <div class="left">left two</div>
</div>
<div class="right">right one</div>
<div class="left">left three</div>
<div class="right">
 <div class="right">right two</div>
 <div class="right">right three</div>
 <div class="right">right four</div>
 <div class="right">right five</div>
</div>

Ответ 6

Ваш вопрос заставил меня задать этот вопрос. У меня есть решение:

  • Используйте CSS flexbox для создания многоколоночного макета (см. следующий маркер по "фактической" причине)
  • Используйте свойство order для сортировки элементов, не зависящих от порядка источника (слева сначала справа)
  • Используйте свойство break-before для принудительного перерыва столбца перед первым правильным элементом

К сожалению, свойство break-* не работает. На данный момент только FireFox, кажется, делает правильные вещи, хотя и использует неправильное свойство.

.wrapper {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
}
.left {
  order: 1;
  width: 50%;
  background: coral;
}
.right {
  order: 2;
  width: 50%;
  background: mediumaquamarine;
}
/* first-of-class selector :p */
.right {
  page-break-before: always;
}
.right ~ .right {
  page-break-before: auto;
}
<div class="wrapper">
  <div class="left">left one</div>
  <div class="left">left two</div>
  <div class="right">right one</div>
  <div class="left">left three</div>
  <div class="right">right two</div>
  <div class="right">right three</div>
  <div class="left">left four</div>
  <div class="right">right four</div>
  <div class="right">right five</div>
  <div class="left">left five</div>
  <div class="right">right six</div>
  <div class="right">right seven</div>
</div>