Главная » Статьи » Преобразование объекта с фиксированными размерами в адаптивный элемент

Преобразование объекта с фиксированными размерами в адаптивный элемент

Преобразование объекта с фиксированными размерами в адаптивный элемент

От автора: недавно я попал в ситуацию, когда хотел показать iPhone на веб-сайте. Я хотел, чтобы пользователи могли взаимодействовать с демо-версией приложения на этом «фиктивном» телефоне, поэтому он должен был отображаться в CSS, а не изображением.

Я нашел отличную библиотеку под названием marvelapp/devices.css. Библиотека реализовала нужное мне устройство с использованием чистого CSS, и они выглядели великолепно, но была проблема: предлагаемые устройства не были адаптивными (то есть их нельзя было масштабировать). В открытом вопросе было перечислено несколько вариантов, но каждый из них был связан с несовместимостью браузеров и другими проблемами. Я решил изменить библиотеку, чтобы сделать устройства адаптивными.

Вот последняя версия библиотеки с изменяемыми размерами. Ниже мы рассмотрим код.

Оригинальная библиотека была написана на Sass и реализовала устройства с использованием элементов с фиксированным размером в пикселях. Авторы также предоставили простой пример HTML для каждого устройства, включая iPhone X, с которым мы будем работать в этой статье. Вот посмотрите на оригинал. Обратите внимание, что устройство, которое здесь отображается, хотя и детализированное, довольно большое и не меняет размеров.

Основной подход

Есть три приема CSS, которые я использовал, чтобы сделать устройства изменяющими размеры:

Функции CSS calc(), которая может выполнять вычисления, даже если входные данные имеют разные единицы измерения

Пользовательское свойство CSS —size-divisor, используемое с функцией var()

@media запросы, разделенные по min-width

Давайте рассмотрим каждый из них.

calc()

Фукнция CSS calc() позволяет изменить размер различных сторон устройства. Функция принимает в качестве входных данных выражение и возвращает оценку функции в качестве выходных данных с соответствующими единицами измерения. Если бы мы хотели сделать устройства меньшими наполовину, нам нужно было бы разделить каждую сторону в пикселях на 2. До:

width: 375px;

После:

width: calc(375px / 2);

Второй фрагмент дает длину, равную половине размера первого фрагмента. Каждую сторону в пикселях в исходной библиотеке необходимо будет обернуть в функцию calc() для изменения размера всего устройства.

var(–size-divisor)

Переменная CSS сначала должна быть объявлена в начале файла, прежде чем она может быть использован в любом месте.

:root { --size-divisor: 3;
}

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

width: calc(375px / var(--size-divisor));

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

@media

Чтобы устройства были адаптивными, они должны реагировать на изменения размера экрана. Мы достигаем этого с помощью медиа-запросов. Эти запросы отслеживают ширину экрана и запускаются, если размер экрана пересекает заданные пороговые значения. Я выбрал контрольные точки на основе размеров Bootstrap для xs, sm и так далее.

Нет необходимости устанавливать контрольную точку на минимальной ширине в ноль пикселей; вместо этого объявление :root в начале файла обрабатывает эти очень маленькие экраны. Эти медиа-запросы должны указываться в конце документа и располагаться в порядке возрастания min-width.

@media (min-width: 576px) { :root { --size-divisor: 2; }
}
@media (min-width: 768px) { :root { --size-divisor: 1.5; }
}
@media (min-width: 992px) { :root { --size-divisor: 1; }
}
@media (min-width: 1200px) { :root { --size-divisor: .67; }
}

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

Предварительная обработка препроцессора с помощью Python

С этими инструментами мне нужен был способ применить мой новый подход к библиотеке из нескольких тысяч строк. Полученный файл будет начинаться с объявления переменной, включать в себя всю библиотеку с каждым измерением пикселей, заключенным в функцию calc(), и завершаться указанными выше медиазапросами.

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

def scale(token): if token[-2:] == ';\n': return 'calc(' + token[:-2] + ' / var(--size-divisor));\n' elif token[-3:] == ');\n': return '(' + token[:-3] + ' / var(--size-divisor));\n' return 'calc(' + token + ' / var(--size-divisor))'

Эта функция, учитывая строку, содержащую NNpx, возвращает calc(NNpx / var(—size-divisor));. Во всем файле, к счастью, есть только три совпадения для пикселей: NNpx, NNpx; и NNpx) ;. Остальное — просто конкатенация строк. Однако эти токены уже были сгенерированы путем разделения каждой строки пробелами.

def build_file(scss): out = ':root {\n\t--size-divisor: 3;\n}\n\n' for line in scss: tokens = line.split(' ') for i in range(len(tokens)): if 'px' in tokens[i]: tokens[i] = scale(tokens[i]) out += ' '.join(tokens) out += "@media (min-width: 576px) {\n \ :root {\n\t--size-divisor: 2;\n \ }\n}\n\n@media (min-width: 768px) {\n \ :root {\n\t--size-divisor: 1.5;\n \ }\n}\n\n@media (min-width: 992px) { \ \n :root {\n\t--size-divisor: 1;\n \ }\n}\n\n@media (min-width: 1200px) { \ \n :root {\n\t--size-divisor: .67;\n }\n}" return out

Функция, которая создает новую библиотеку, начинается с объявления переменной CSS. Затем она перебирает всю старую библиотеку в поисках измерений в пикселях, чтобы масштабировать их. Для каждого из найденных сотен токенов, она определяет те, которые содержат px и масштабирует их. По мере выполнения итерации функция сохраняет исходную структуру строки, соединяя токены. Наконец, она добавляет необходимые медиа-запросы и возвращает всю библиотеку в виде строки. Небольшой код для запуска функций, чтения и записи из файлов завершает работу.

if __name__ == '__main__': f = open('devices_old.scss', 'r') scss = f.readlines() f.close() out = build_file(scss) f = open('devices_new.scss', 'w') f.write(out) f.close()

Этот процесс создает новую библиотеку в Sass. Чтобы создать файл CSS для окончательного использования, запустите:

sass devices_new.scss devices.css

Эта новая библиотека предлагает те же устройства, но они адаптивны:

Чтобы просмотреть фактический выходной файл, состоящий из тысяч строк, найдите его на GitHub.

Другие подходы

В то время как результаты этого процесса довольно убедительны, получить их было не так просто. Почему я не выбрал более простой подход? Вот еще три подхода с их преимуществами и недостатками.

zoom

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

Однако это не подходит по простой причине: zoom является нестандартным свойством. Среди других ограничений, оно не поддерживается в Firefox.

Заменить px на em

Другой подход поиска и замены предусматривает замену всех вхождений px на em. Затем устройства сжимаются и растягиваются в соответствии с размером шрифта. Тем не менее, чтобы сделать их достаточно маленькими для размещения на мобильном дисплее, может потребоваться незначительный размер шрифта, меньший, чем минимальные размеры браузеров, таких как Chrome. При таком подходе могут возникнуть проблемы, если посетитель вашего сайта использует вспомогательные технологии, которые увеличивают размер шрифта.

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

scale()

Функция scale() может изменять размер целых объектов. Функция возвращает <transform-function>, который может быть передан атрибуту transform в стиле. В целом, это мощный подход, но он не меняет фактическое измерение устройства CSS. Я предпочитаю свой подход, особенно при работе со сложными элементами интерфейса, отображаемыми на «экране» устройства.

Крис Койер подготовил пример, используя этот подход.

В заключение

Сотни вызовов calc()могут быть не первым инструментом, к которому я бы обратился, если бы реализовал эту библиотеку с нуля, но в целом это эффективный подход для изменения размеров существующих библиотек. Добавление переменных и медиа-запросов делает объекты адаптивными. Если базовая библиотека будет обновлена, скрипт Python сможет обработать эти изменения в новой версии нашей адаптивной библиотеки.

Автор: Philip Kiely

Источник: https://css-tricks.com

Редакция: Команда webformyself.