Condesandbox как разместить браузер справа

Обновлено: 07.07.2024

Узнайте, как создать анимированное закрываемое боковое навигационное меню на сайте.

Sidenav overlay
Sidenav overlay without animation
Sidenav push (off-canvas)
Sidenav push w/opacity
Sidenav full-width
Попробуйте сами »

Создать анимированную боковую навигацию

Шаг 1) Добавить HTML:

Пример

<!-- Используйте любой элемент, чтобы открыть sidenav -->
<span onclick="openNav()">open</span>

<!-- Добавьте весь контент страницы внутри этого div, если вы хотите, чтобы боковая навигация выдвигала контент страницы вправо (не используется, если вы хотите, чтобы sidenav находился сверху страницы -->
<div > .
</div>

Шаг 2) Добавить CSS:

Пример

/* Положение и стиль кнопки закрытия (верхний правый угол) */
.sidenav .closebtn position: absolute;
top: 0;
right: 25px;
font-size: 36px;
margin-left: 50px;
>

/* На экранах меньшего размера, где высота меньше 450px, измените стиль sidenav (меньше отступов и меньший размер шрифта) */
@media screen and (max-height: 450px) .sidenav
.sidenav a
>

Шаг 3) Добавить JavaScript:

Пример ниже выскальзывает в боковой навигации и делает его шириной 250 пикселей:

Оверлей боковой навигаци. Пример

/* Установите ширину боковой навигации до 250 пикселей */
function openNav() document.getElementById("mySidenav").style.width = "250px";
>

/* Установите ширину боковой навигации на 0 */
function closeNav() document.getElementById("mySidenav").style.width = "0";
>

Приведенный ниже пример перемещает боковую навигацию и сдвигает содержимое страницы вправо (значение, используемое для установки ширины sidenav, также используется для установки левого поля "страницы из содержимым"):

Боковая навигация выталкивает контент

/* Установите ширину боковой навигации 250 пикселей, и левый край содержимого страницы - 250 пикселей. */
function openNav() document.getElementById("mySidenav").style.width = "250px";
document.getElementById("main").style.marginLeft = "250px";
>

/* Установите ширину боковой навигации равной 0, и левое поле содержимого страницы - 0. */
function closeNav() document.getElementById("mySidenav").style.width = "0";
document.getElementById("main").style.marginLeft = "0";
>

Приведенный ниже пример также перемещает боковую навигацию и перемещает содержимое страницы вправо, только на этот раз мы добавляем черный цвет фона с непрозрачностью 40% к элементу body, чтобы "выделить" боковую навигацию:

Боковая навигация выталкивает контент с непрозрачностью

/* Установите ширину боковой навигации 250 пикселей, и левое поле содержимого страницы - 250 пикселей и добавьте черный цвет фона к телу. */
function openNav() document.getElementById("mySidenav").style.width = "250px";
document.getElementById("main").style.marginLeft = "250px";
document.body.style.backgroundColor = "rgba(0,0,0,0.4)";
>

/* Установите ширину боковой навигации равной 0, и левое поле содержимого страницы - 0, и цвет фона тела - белым. */
function closeNav() document.getElementById("mySidenav").style.width = "0";
document.getElementById("main").style.marginLeft = "0";
document.body.style.backgroundColor = "white";
>

Пример ниже скользит в боковой навигации слева и охватывает всю страницу (ширина 100%):

Боковая навигация на всю ширину:

/* Открыть боковую навигацию */
function openNav() document.getElementById("mySidenav").style.width = "100%";
>

/* закрыть/скрыть боковую навигацию */
function closeNav() document.getElementById("mySidenav").style.width = "0";
>

Пример ниже открывает и закрывает боковое меню навигации без анимации:

Боковая навигация без анимации

/* Открыть боковую навигацию */
function openNav() document.getElementById("mySidenav").style.display = "block";
>

/* Закрыть/скрыть боковую навигацию */
function closeNav() document.getElementById("mySidenav").style.display = "none";
>

В приведенном ниже примере показано, как создать правое навигационное меню:

Правосторонняя навигация:

В приведенном ниже примере показано, как создать боковое навигационное меню, которое всегда отображается (зафиксировано):

Всегда отображать боковую навигацию:

Совет: Посетите CSS Навбар учебник чтобы узнать больше о панелях навигации на нашем сайте W3Schools на русском.

Вёрстка таких окон сначала кажется простой задачей. Модальные окна можно сделать даже без помощи JS только лишь с помощью CSS, но на практике они оказываются неудобными, и из-за маленьких недочетов модальные окна раздражают посетителей сайта.

В итоге было задумано сделать собственное простое решение.


Вообще говоря, есть несколько готовых скриптов, JavaScript библиотек, реализующих функционал модальных окон, например:

  • Arctic Modal,
  • jquery-modal,
  • iziModal,
  • Micromodal.js,
  • tingle.js,
  • Bootstrap Modal (из библиотеки Bootstrap) и др.

(в статье не рассматриваем решения на базе Frontend-фреймворков)

Несколькими из них я пользовался сам, но почти у всех находил какие-то недостатки. Некоторые из них требуют подключения библиотеки jQuery, которая есть не на всех проектах. Для разработки своего решения, нужно сначала определиться с требованиями.

Что мы ждём от модальных окон? Отвечая на этот вопрос, я основывался на докладе «Знакомьтесь, модальное окно» Анны Селезнёвой, а так-же на относительно старой статье NikoX «arcticModal — jQuery-плагин для модальных окон».

Итак, чтобы нам хотелось видеть?

Дисклеймер: Прежде чем мы рассмотрим подробности, сразу дам ссылку на готовый код получившейся библиотеки (HystModal) на GitHub, а также ссылку на демо+документацию.

Начнём с разметки.

1. Разметка HTML и CSS

1.1. Каркас модальных окон

Как открыть окно быстро? Самое простое решение: разместить всю разметку модального окна сразу в HTML странице. Затем скрывать/показывать это окно при помощи переключения классов CSS.

Набросаем такую разметку HTML (я назвал этот скрипт «hystmodal»):

Сделаем так, чтобы .hystmodal растягивался на всё окно браузера и закрывал собой содержимое страницы. Чтобы этого добиться, установим фиксированное позиционирование в CSS и приравняем свойства top, bottom, left и right к нулю.

В этом коде сделаны ещё две вещи:

  1. Так как мы хотим центрировать окно внутри страницы, превращаем .hystmodal в flex-контейнер с выравниваем его потомков по центру по вертикали и горизонтали.
  2. Окно может быть больше высоты экрана браузера, поэтому мы устанавливаем overflow-y: auto , чтобы при переполнении возникала полоса прокрутки. Также, для сенсорных экранов (в основном для Safari) нам стоит установить свойство -webkit-overflow-scrolling: touch , чтобы сенсорная прокрутка работала именно на этом блоке а не на странице.

Теперь установим стили для самого окна.

Кажется возникли сложности.

Проблема №1. Если высота окна больше высоты окна браузера, то контент окна будет обрезан сверху.


Это возникает из-за свойства justify-content: center . Оно позволяет нам удобно выровнять потомков по основной оси (по вертикали), но если потомок становится больше родителя то часть его становится недоступной даже при прокручиваемом контейнере. Подробнее можно посмотреть на stackoverflow. Решение – установить justify-content: flex-start , а потомку установить margin:auto . Это выровняет его по центру.

Проблема №2. В ie-11 если высота окна больше высоты окна браузера, то фон окна обрезается.

Решение: мы можем установить flex-shrink:0 потомку – тогда обрезки не происходит.

Проблема №3. В браузерах кроме Chrome нет отступа от нижней границы окна (т.е. padding-bottom не сработал).

Сложно сказать баг это браузеров или наоборот соответствует спецификации, но решения два:

  • установить псевдоэлемент ::after после потомка и дать ему высоту вместо padding
  • обернуть элемент в дополнительный блок и дать отступы уже ему.

Воспользуемся вторым методом. Добавим обертку .hystmodal__wrap . Так мы заодно обойдём и проблему №1, а вместо padding у родителя установим margin-top и margin-top у самого .hystmodal__window .

Наш итоговый html:

В код также добавлены некоторые aria и role атрибуты для обеспечения доступности.

Обновленный код CSS для обертки и окна.

1.2 Скрываем окно

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

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

Нам поможет другое свойство visibility:hidden . Оно скроет окно визуально, хотя и зарезервирует под него место. А так как все будущие окна на странице имеют фиксированное
позиционирование – они будут полностью скрыты и не повлияют на остальную страницу. Кроме того, на элементы с visibility:hidden нельзя установить фокус с клавиатуры, а от скрин-ридеров мы уже скрыли окна с помощью атрибута aria-hidden="true" .

Добавим также классы для открытого окна:

1.3 Оформление подложки

В лучшем случае, нам нужен отдельный html-элемент в качестве оверлея. Можно использовать и имеющийся элемент модального окна .hystmodal в качестве оверлея, но тогда анимация на этом элементе (например переход opacity) будет затрагивать и внутренние элементы. В итоге, не получится анимировать разные свойства для окна и оверлея отдельно.

Просто разместим элемент .hystmodal__shadow прямо перед закрывающим </body> . В будущем, сделаем так, чтобы этот элемент создавался автоматически из js при инициализации библиотеки.

1.4 Отключение прокрутки страницы

Когда модальное окна открывается, мы хотим, чтобы страница под ним не прокручивалась.
Самый простой способ этого добиться — повесить overflow:hidden для body или html, когда окно открывается. Однако с этим есть проблема:

Проблема №4. В браузере Safari на iOS страница будет прокручиваться, даже если на тег html или body повешен overflow:hidden .
Решается двумя способами, либо блокированием событий прокрутки (touchmove, touchend или touchsart) из js вида:

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

ps: можно конечно применить библиотеку scroll-lock, в которую заложено это решение, но в статье было решено воспользоваться другим вариантом.

Другое решение – основано частично на CSS. Пусть когда окно открывается, на элемент <html> будет добавляться класс .hystmodal__opened :

Благодаря position:fixed , окно не будет прокручиваться даже в safari, однако здесь тоже не всё гладко:

Проблема №5. При открытии/закрытии окна страница прокручивается в начало.
Действительно, это происходит из-за изменения свойства position, текущая прокрутка окна сбрасывается.

Для решения, нам нужно написать следующий JS (упрощенно):

При открытии:

При закрытии:

Отлично, приступим к JavaScript коду.

2. Код JavaScript

2.2 Каркас библиотеки

Нам нужна совместимость со старыми браузерами включая IE11 поэтому нам нужно выбрать из 2 вариантов кодинга:

  • Разрабатывать на старом стандарте ES5, и использовать только те фичи, которые поддерживают все браузеры.
  • Применить современный синтаксис ES6, но подключить транспайлер Babel, который автоматически преобразует код для всех браузеров и встроит необходимые полифилы.
    Было принято решение использовать второй вариант, с прицелом на будущее.
    Приступим.

Основа нашей библиотеки единственный класс HystModal . Ниже я приведу скелет кода с комментариями, а потом добавим остальной функционал.

Итак, мы описали класс HystModal . Чтобы всё работало, нужно всего лишь подключить наш скрипт и создать экземпляр класса:

Проблема №6: если в браузере есть фиксированный скроллбар (который влияет на ширину страницы), то при открытии/закрытии окна происходит сдвиг контента, когда полоса прокрутки то появляется то пропадает.

Действительно – скроллбар пропадает и контент страницы перераспределяется. Чтобы решить эту проблему, можно добавить отступ справа к тегу html, равный ширине скроллбара когда он пропадает.

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

Дополним метод _bodyScrollControl()

Почему код метода close() упрощён? Дело в том, что просто убирая классы CSS у элементов, мы не можем анимировать закрытие окна.

Проблема №7. При закрытии окна, свойство visibility:hidden применяется сразу и не даёт возможности анимировать закрытие окна.

Причина этого известна: свойство visibility:hidden не анимируется. Конечно, можно обойтись без анимации, но, если она нужна, сделаем следующее.

  • Создадим дополнительный CSS-класс .hystmodal—moved почти такой-же как и .hystmodal--active
  • Затем при закрытии сначала добавим этот класс к окну и повесим обработчик события «transitionend» на модальном окне. Затем удалим класс `.hystmodal—active , таким образом вызывая css-переход. Как только переход завершится, сработает обработчик события «transitionend», в котором сделаем всё остальное и удалим сам обработчик события.

Ниже: новая версия методов закрытия окна:

Вы заметили, что мы создали ещё один метод _closeAfterTransition() и перенесли основную логику закрытия туда. Это нужно, чтобы удалить обработчик события transitionend после закрытия окна, ведь в метод removeEventListener необходимо передать именно ту функцию, которую мы привязывали.

Кроме того, если анимация не будет нужна, можно просто вызвать this._closeAfterTransition() не вешая его на событие.

Как мы помним, внутри addEventListener, this будет указывать на селектор где происходит событие, а не на наш экземпляр класса, поэтому в конструкторе нужно добавить ещё одну строчку для жёсткой привязки метода к this.

2.2 Закрытие окна по клику на оверлей

Нам нужно обработать ещё одно событие – закрытие окна по клику на элемент подложки .hystmodal__wrap . Мы можем повесить обработчик клика на документ для делегирования события как при открытии и проверить что событие произошло на .hystmodal__wrap примерно так:

Это будет работать, но есть один малозаметный недостаток.

Проблема №8. Если кнопку мыши нажать внутри окна, а отпустить за его пределами (над подложкой), окно закрывается.

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

Окно закрывается потому что по спецификации, если нажатие и отпускание мыши были на разных элементах, то событие click сработает на самом ближайшем общем для них элементе, а у нас это как раз .hystmodal__wrap .

Мы могли бы решить это изменением html, добавляя ещё один div сразу после .hystmodal__window и размещая его визуально под окном. Но нам бы не хотелось добавлять лишний пустой div ещё сильнее усложняя разметку.

Мы можем разбить наш addEventListener на два отдельных обработчика: для событий mousedown и mouseup и будем проверять чтобы оба события происходили именно на .hystmodal__wrap . Добавим новые обработчики событий в наш метод eventsFeeler()

2.3 Управление фокусом

У нас заготовлено два метода для управления фокусом: focusContol() для переноса фокуса внутрь окна и обратно при его закрытии, а также focusCatcher(event) для блокирования ухода фокуса из окна.

Решения для фокуса были реализованы аналогично js-библиотеке «Micromodal» (Indrashish Ghosh). А именно:

1. В служебный массив сохраним все css селекторы на которых может быть установлен фокус (свойство помещаем в init()):

2. В методе focusContol() находим первый такой селектор в окне и устанавливаем на него фокус, если окно открывается. Если же окно закрывается – то переводим фокус на this.starter :

3. В методе focusCatcher() находим в окне и превращаем в массив коллекцию всех элементов на которых может быть фокус. И проверяем, если фокус должен был выйти на пределы окна, то вместо этого устанавливаем фокус снова на первый или последний элемент (ведь фокус можно переключать как по Tab так и по Shift+Tab в обратную сторону).

Результирующий код метода focusCatcher:

По сути мы реализовали все необходимое для успешного создания модальных окон, осталось ещё несколько дел:

Проблема №9. В IE11 не работают методы Element.closest() и Object.assign() .

Для поддержки Element.closest, воспользуемся полифилами для closest и matches от MDN.

Можно их вставить просто так, но так как у нас проект всё равно собирается webpack, то удобно воспользоваться пакетом element-closest-polyfill который просто вставляет этот код.

Для поддержки Object.assign , можно воспользоваться уже babel-плагином @babel/plugin-transform-object-assign

3. Заключение и ссылки

Повторяя начало статьи, всё изложенное выше, я оформил в маленькую библиотеку hystModal под MIT-лицензией. Вышло 3 кБ кода при загрузке с gzip. Ещё написал для неё подробную документацию на русском и английском языке.

Что вошло ещё в библиотеку hystModal, чего не было в статье:

  • Настройки (вкл/выкл управление фокусом, варианты закрытия, ожидание анимации закрытия)
  • Коллбеки (функции вызывающиеся перед открытием окна и после его закрытия (в них передаётся объект модального окна))
  • Добавлен запрет на какие-либо действия пока анимация закрытия окна не завершится, а также ожидание анимации закрытия текущего окна перед открытием нового (если окно открывается из другого окна).
  • Оформление кнопки-крестика закрытия в CSS
  • Минификация CSS и JS плагинами Webpack.

Если вам будет интересна эта библиотека, буду рад звёздочке в GitHub, или напишите в Issues о найденных багах. (Особенно большие проблемы, наверное, в грамматике английской версии документации, так как мои знания языка пока на начальном уровне. Связаться со мной также можно в Instagram

Очень часто стоит задача выровнять блок по центру страницы / экрана, да ещё и так, чтобы без ява-скрипта, без задания жёстких размеров или отрицательных отступов, ещё чтобы и скроллбары работали у родителя, если блок превышает его размеры. В сети ходят достаточно много однообразных примеров как выровнять блок по центру экрана. Как правило большинство из них основаны на одних принципах.

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

Вариант 1. Отрицательный отступ.

Позиционируем блок атрибутами top и left на 50%, и заранее зная высоту и ширину блока, задаём отрицательный margin, который равен половине размера блока. Огромным минусом данного варианта является то, что нужно подсчитывать отрицательные отступы. Так же блок не совсем корректно ведёт себя в окружении скроллбаров — он попросту обрезается так как имеет отрицательные отступы.

Вариант 2. Автоматический отступ.

Менее распространённый, но схожий с первым. Для блока задаём ширину и высоту, позиционируем атрибутами top right bottom left на 0, и задаём margin auto. Плюсом данного варианта являются рабочие скроллбары у родителя, если у последнего задана 100% ширина и высота. Минусом данного способ является жёсткое задание размеров.

Вариант 3. Таблица.

Задаём родителю табличные стили, ячейке родителя устанавливаем выравнивание текста по центру. А блоку задаём модель строчного блока. Минусами мы получаем не рабочие скроллбары, и в целом не эстетичность «эмуляции» таблицы.

Вариант 4. Псевдо-элемент.

Данный вариант лишён всех проблем, перечисленных у предыдущих способов, а так же решает первоначально поставленные задачи. Суть состоит в том, чтобы у родителя задать стили псевдо-элементу before, а именно 100% высоту, выравнивание по центру и модель строчного блока. Так же само и у блока ставится модель строчного блока, выравнивание по центру. Чтобы блок не «падал» под псевдо-элемент, когда размеры первого больше чем родителя, указываем родителю white-space: nowrap и font-size: 0, после чего у блока отменяем эти стили следующими — white-space: normal. В данном примере font-size: 0 нужен для того, чтобы убрать образовавшийся пробел между родителем и блоком в связи с форматированием кода. Пробел можно убрать и иными способами, но лучшим считается просто его не допускать.

либо, если вам нужно, чтобы родитель занимал только высоту и ширину окна, а не всей страницы:

Вариант 5. Flexbox.

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

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

Вариант 6. Transform.

Подходит в случае если мы ограничены структурой, и нет возможности манипулировать родительским элементом, а блок выровнять как-то нужно. На помощь придёт css функция translate() . При значение 50% абсолютное позиционирование расположит верхний левый угол блока точно по центру, затем отрицательное значение translate сдвинет блок относительно своих собственных размеров. Учтите, что могут всплыть негативные эффекты в виде размытых граней или начертания шрифта. Также подобный способ может привести к проблемах с вычислением положения блока с помощью java-script'а. Иногда для компенсации потери 50% ширины из-за использования css свойства left может помочь заданное у блока правило: margin-right: -50%; .

Вариант 7. Кнопка.

Пользователь azproduction предложил вариант, где блок обрамляется в тег button. Кнопка имеет свойство центрировать всё, что находится у неё внутри, а именно элементы строчной и блочно-строчной (inline-block) модели. На практике использовать не рекомендую.

  • Боковые колонки имеют постоянный размер, а центральная растягивается между ними на весь экран
  • Центральная колонка расположена первой в коде
  • Все блоки равной высоты на весь экран
  • Минимум хаков под старые версии

Мы имеем стандартный шаблон со следующим кодом, но первым блоком контейнера идет центр:

1. Создадим фреймы

Для начала пропишем дивы шапки сайта, контейнер для основной начинки и подвал для различной информации:

Для блока контейнера выставляем отступы от краев, чтобы потом в них поместить сайдбары:

На картинке это выглядит следующим образом:

2. Добавление колонок

Теперь добавим колонки к существующему коду:

И отредактируем стили. Выставим ширину и позиционирование. Также добавим очищение позиционирования для подвала чтобы сохранить стилистику:

Отмечу что 100% ширина на центральной колонке относится к контейнеру div, но исключая отступы. Блоки выстраиваются по очереди, но поскольку центр занимает 100% ширины левая и правая колоки располагаются после центра, ниже.

3. Расстановка боковых колонок по местам

Осталось только расставить колонки таким образом, чтобы они выстроились в линию с отступами контейнера. Колонка центра начинается там, где это должна быть, следовательно мы сосредоточимся на левой колонке. Для установки левой колонки налево мы выставим отрицательный левый margin для левой колонки размером с центральную колонку:

Теперь левая колонка накладывается на колонку центра, по ее левому краю и выглядит это так:

4. Устанавливаем правую колонку на место.

Левая колонка встала на свое место, теперь возьмемся за правую. Чтобы ее поставить на место мы должны установить отрицательный отступ справа по примеру левой колонки.

Теперь все колонки на своих местах, выстроены в линию и выглядит это так:

5. Немного улучшим дизайн.

Но мы используем хак для совместимости с IE6

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

Отступы центра требует немного большей изобретательности. Отступы центра плюс ширина 100 % заставляет колонку центра расширяться вне своей ширины контейнера. Чтобы вернуть это место назад, нужно увеличить край общей суммой отступов. Это гарантирует, что колонка центра будет такого же размера как нам нужно. Сделаем отступ с каждой стороны по 10px+10px=20px, также по 10px+10px от центрального блока до сайдбаров. Итого 40px. Отступы снизу и сверху ставятся без проблем любого размера.

min-width : 630px ; > /* 2x (LC fullwidth + CC padding) + RC fullwidth */

Блоки div одинаковой высоты

Высоту блоков я выставляю через фикс отступов. Главное чтобы Х не был равен реальной высоте страницы.

Если понадобится какое-то хитрое позиционирование внутри подвала лучше использовать div внутри дива:

Например чтобы подвал растянулся по низу:

Другие интересные записи:

Отменить ответ

Интересный способ компоновки макета, но вот выравнивание колонок по низу через задание дико большого отступа это просто сокрытие концов колонок за границей общего для них дива, на самом деле они не равны. Это так называемый псевдо-способ, довольно обширно описанный в Интернете. Есть ли более правильный и более надежный способ выравнять три колонки по высоте, при этом заливая их разным цветом и включая или отключая по мере надобности — делая то 2 колонки, то 3, то 1, в зависимости от выбора через менню. (не используя слишком большие отступы)? Если можно продублируйте, пожалуйста, ответ на E-mail.

Читайте также: