2015-08-21 2 views
2

мне удалось получить CSS3 к почти делать то, что я хочу:Держите элемент центрированного между или выше, два другими элементом

  1. серого .top-middle контейнера произвольной ширины, и всегда должно оставаться заподлицо с верхним краем родительского контейнера (<main>).
  2. Пурпурный левый и правые контейнеры также имеют произвольную ширину и должны всегда оставаться на одном уровне с соответствующими краями родительского контейнера.
  3. Когда родительский контейнер достаточно широк, три верхних контейнера должны располагаться бок о бок; в противном случае осталось и правая контейнеры должны располагаться под контейнером .top-middle. (Было бы неплохо, если бы оба фиолетовых контейнера упали одновременно, но я буду жить, когда один из них останется рядом с средним контейнером, когда есть место.)
  4. Минимальная ширина контейнера <main> должна быть по существу ширина .top-middle контейнера
  5. .top-middle контейнер должен быть по центру, в идеале относительно родительского контейнера (<main>), но, по крайней мере, по отношению к горизонтальному пространству, доступная для него (между влево и правильных контейнеров)

Это последнее требование, № 5, что я не справился.

Я бы предпочел не прибегать к JavaScript, и, конечно же, это должно быть кросс-браузерное решение. (Меня не волнует IE < 11, хотя люди, использующие этот рывок, больше беспокоятся, чем мои симпатичные!)

N.B. Эту проблему нельзя проверить (AFAIK) в jsfiddle, функцию фрагмента кода StackOverflow или любую другую среду с фиксированной шириной. Скопируйте мой код и вставьте его в файл и посмотрите, что происходит, когда вы расширяете или сужаете окно браузера.

Вот мой полный код, для копирования и вставки удовольствия:

main div { 
 
    white-space: nowrap; 
 
    color: white; 
 
} 
 
.top-container { 
 
    background: olive; 
 
} 
 
.top-middle { 
 
    background: grey; 
 
} 
 
.top-left, 
 
.top-right { 
 
    background: purple; 
 
} 
 
.bottom-container { 
 
    background: blue; 
 
    text-align: center; 
 
} 
 
/* The crux of the layout starts here */ 
 

 
main { 
 
    height: 300px; 
 
    display: flex; 
 
    flex-direction: column; 
 
} 
 
.top-container>* { 
 
    display: inline-block; 
 
    padding: 1em; 
 
} 
 
.top-left { 
 
    float: left; 
 
} 
 
.top-right { 
 
    float: right; 
 
} 
 
.spacer { 
 
    background: silver; 
 
    flex-grow: 1; 
 
}
<main> 
 
    <div class="top-container"> 
 
    <div class="top-middle"> 
 
     This should be centred, and always stay on top. 
 
     <em>Left</em> and <em>right</em> should drop when the window contracts. 
 
    </div> 
 
    <div class="top-left">left</div> 
 
    <div class="top-right">right</div> 
 
    </div> 
 
    <div class="spacer"></div> 
 
    <div class="bottom-container">This is the bottom.</div> 
 
</main>

+1

Не могли бы вы положить это в jsfiddle так ли WOU ld будет проще отлаживать –

+0

@MattStephens: Я приветствую вас сделать это (как это сделал Крис ниже), но я не уверен, что вы сможете проверить все требования - я не уверен, что вы можете изменять размеры контейнеров в JSFiddle , Во всяком случае, редактирование файла и обновление страницы в браузере довольно просто. –

+0

Используйте медиа-запрос и определите стиль именно для каждого размера. – wwwmarty

ответ

1

Ваше пятое требование может быть достигнуто путем следующих изменений:

  • Добавить text-align: center; к .top-container

Это работает, потому что text-align эффекты выравнивание inline элементов:

text-align CSS свойство описывает, как встроенный контент, как текст, выравнивается в его паре t элемент блока. text-align не контролирует выравнивание самих элементов блока, а только их встроенное содержимое.

выравнивание текста (https://developer.mozilla.org/en-US/docs/Web/CSS/text-align)

.top-middle установлено быть inline-block из-за .top-container>* { display: inline-block; padding: 1em; } так будет центрирована в пределах .top-container.

main div { 
 
    white-space: nowrap; 
 
    color: white; 
 
} 
 
.top-container { 
 
    background: olive; 
 
    text-align: center; 
 
} 
 
.top-middle { 
 
    background: grey; 
 
} 
 
.top-left, 
 
.top-right { 
 
    background: purple; 
 
} 
 
.bottom-container { 
 
    background: blue; 
 
    text-align: center; 
 
} 
 
/* The crux of the layout starts here */ 
 

 
main { 
 
    height: 300px; 
 
    display: flex; 
 
    flex-direction: column; 
 
} 
 
.top-container>* { 
 
    display: inline-block; 
 
    padding: 1em; 
 
} 
 
.top-left { 
 
    float: left; 
 
} 
 
.top-right { 
 
    float: right; 
 
} 
 
.spacer { 
 
    background: silver; 
 
    flex-grow: 1; 
 
}
<main> 
 
    <div class="top-container"> 
 
    <div class="top-middle"> 
 
     This should be centred, and always stay on top. 
 
     <em>Left</em> and <em>right</em> should drop when the window contracts. 
 
    </div> 
 
    <div class="top-left">left</div> 
 
    <div class="top-right">right</div> 
 
    </div> 
 
    <div class="spacer"></div> 
 
    <div class="bottom-container">This is the bottom.</div> 
 
</main>

К сожалению, есть недостаток этого метода в качестве ошибки в Firefox всегда заставит .top-left и .top-right на новую строку:

затрагивающего также сам Bugzilla, а glob указал на IRC. https://bugzilla.mozilla.org/show_bug.cgi?id=677757#c4 имеет «комментарий 4» Текст скрыт

Причина этого кода в nsLineLayout :: ReflowFrame:

if (psd->mNoWrap) { 
    // If we place floats after inline content where there's 
    // no break opportunity, we don't know how much additional 
    // width is required for the non-breaking content after the float, 
    // so we can't know whether the float plus that content will fit 
    // on the line. So for now, don't place floats after inline 
    // content where there's no break opportunity. This is incorrect 
    // but hopefully rare. Fixing it will require significant 
    // restructuring of line layout. 
    // We might as well allow zero-width floats to be placed, though. 
    availableWidth = 0; 
} 

Интересно ли то, что нужно сделать, это:
* не манипулируют доступную ширину вообще, или
* сделать имеющаяся ширина бесконечна, так как содержание Nowrap никогда не будет обтекать поплавок все равно

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

Ошибка 488725 - поплавок сдвинут вниз по одной линии с пробелом: nowrap; (https://bugzilla.mozilla.org/show_bug.cgi?id=488725)

Вы также можете использовать flex к центру .top-middle хотя это обыкновение толкать как .top-left и .top-right вниз к новой линии, когда пространство принято.Для достижения этой цели сделать следующие изменения:

  • Добавить display: flex; в .top-container, чтобы его дети используют модель Flexbox
  • Добавить flex-wrap: wrap; в .top-container, чтобы его дети переносятся на новые линии, когда они бегут из космоса
  • Добавить justify-content: space-between; в .top-container добавить пространство вокруг дочерних элементов, которые будут центрирования .top-middle

main div { 
 
    white-space: nowrap; 
 
    color: white; 
 
} 
 
.top-container { 
 
    background: olive; 
 
    display: flex; 
 
    flex-wrap: wrap; 
 
    justify-content: space-between; 
 
} 
 
.top-middle { 
 
    background: grey; 
 
} 
 
.top-left, 
 
.top-right { 
 
    background: purple; 
 
} 
 
.bottom-container { 
 
    background: blue; 
 
    text-align: center; 
 
} 
 
/* The crux of the layout starts here */ 
 

 
main { 
 
    height: 300px; 
 
    display: flex; 
 
    flex-direction: column; 
 
} 
 
.top-container>* { 
 
    display: inline-block; 
 
    padding: 1em; 
 
} 
 
.top-left { 
 
    float: left; 
 
} 
 
.top-right { 
 
    float: right; 
 
} 
 
.spacer { 
 
    background: silver; 
 
    flex-grow: 1; 
 
}
<main> 
 
    <div class="top-container"> 
 
    <div class="top-left">left</div> 
 
    <div class="top-middle"> 
 
     This should be centred, and always stay on top. 
 
     <em>Left</em> and <em>right</em> should drop when the window contracts. 
 
    </div> 
 
    <div class="top-right">right</div> 
 
    </div> 
 
    <div class="spacer"></div> 
 
    <div class="bottom-container">This is the bottom.</div> 
 
</main>

Чтобы получить как .top-left и .top-right перейти на новую строку, когда они бегут из пространства, вы должны будете использовать JavaScript. Следующее использует ванильный JavaScript, но должно быть хорошей отправной точкой. В принципе:

  • Мы проверяем, если комбинированная ширина .top-left, .top-middle и .top-right равно или больше, чем .top-container
    • Если то изменить order из .top-left и .top-right к разместите их после .top-middle. Добавим margin к .top-left, чтобы заставить его на новую строку и margin в .top-middle центрировать его (так как нет никаких элементов в одной и той же линии для justify-content: space-between; для работы)
    • Если это не мы устанавливаем стили обратно по умолчанию

var topContainer = document.getElementsByClassName('top-container')[0]; 
 
var topLeft = document.getElementsByClassName('top-left')[0]; 
 
var topMiddle = document.getElementsByClassName('top-middle')[0]; 
 
var topRight = document.getElementsByClassName('top-right')[0]; 
 
var topContainerWidth; 
 
var topLeftWidth = topLeft.offsetWidth; 
 
var topMiddleWidth = topMiddle.offsetWidth; 
 
var topRightWidth = topRight.offsetWidth; 
 
var moveDivs; 
 
(moveDivs = function(){ 
 
    topContainerWidth = topContainer.offsetWidth; 
 
    if ((topLeftWidth + topMiddleWidth + topRightWidth) >= topContainerWidth) { 
 
    topLeft.style.order = 1; 
 
    topLeft.style.marginRight = topRightWidth + 'px'; 
 
    topMiddle.style.margin = '0 auto'; 
 
    topRight.style.order = 2; 
 
    } else { 
 
    topLeft.style.order = 0; 
 
    topLeft.style.marginRight = 0; 
 
    topMiddle.style.margin = 0; 
 
    topRight.style.order = 2; 
 
    } 
 
})(); 
 

 
window.addEventListener('resize', function(event){ 
 
    moveDivs(); 
 
});
main div { 
 
    white-space: nowrap; 
 
    color: white; 
 
} 
 
.top-container { 
 
    background: olive; 
 
    display: flex; 
 
    flex-wrap: wrap; 
 
    justify-content: space-between; 
 
} 
 
.top-middle { 
 
    background: grey; 
 
} 
 
.top-left, 
 
.top-right { 
 
    background: purple; 
 
} 
 
.bottom-container { 
 
    background: blue; 
 
    text-align: center; 
 
} 
 
/* The crux of the layout starts here */ 
 

 
main { 
 
    height: 300px; 
 
    display: flex; 
 
    flex-direction: column; 
 
} 
 
.top-container>* { 
 
    display: inline-block; 
 
    padding: 1em; 
 
} 
 
.top-left { 
 
    float: left; 
 
} 
 
.top-right { 
 
    float: right; 
 
} 
 
.spacer { 
 
    background: silver; 
 
    flex-grow: 1; 
 
}
<main> 
 
    <div class="top-container"> 
 
    <div class="top-left">left</div> 
 
    <div class="top-middle"> 
 
     This should be centred, and always stay on top. 
 
     <em>Left</em> and <em>right</em> should drop when the window contracts. 
 
    </div> 
 
    <div class="top-right">right</div> 
 
    </div> 
 
    <div class="spacer"></div> 
 
    <div class="bottom-container">This is the bottom.</div> 
 
</main>

+0

Это не работает, из-за второе предложение, которое вы указали: «text-align не контролирует выравнивание самих элементов блока, а только их встроенное содержимое». Это может быть не очевидно в узком окне выше, но это сам блок, который не центрирован. Сохраните свой код в файле и убедитесь сами: я пробовал его в трех браузерах. –

+0

@MichaelScheper Если вы сделаете это в полноэкранном режиме (нажмите ссылку «Полная страница» вверху справа), вы увидите, что он работает. Он делает это, потому что вы установили '.top-middle' в' inline-block', что делает его «встроенным». –

+0

@MichaelScheper Сохраняет код, запускает его локально и может подтвердить, что он также работает. Если он не работает для вас (либо в стеке, либо в локальном режиме), то на вашем компьютере должно быть что-то в игре. –

0

Я переставить разметку и использовать display: table-cell. Вот пример скрипки http://jsfiddle.net/k108vt58/. Надеюсь, что это помогает и является тем, что вы ищете.

+0

Спасибо, но это нарушает требование №3. Когда я сжимаю основной контейнер, левый и правый элементы не выпадают - правый нарушает контейнер. (Я не уверен, что это можно проверить в JSFiddle, но когда я копирую ваш код в файл и проверяю его в браузере, это становится очевидным, когда я сжимаю окно браузера.) –