Chulakov Dev
1.21K subscribers
112 photos
3 videos
192 links
Канал команды разработки Студии Олега Чулакова.

Советы по Frontend- и Backend-разработке web-сервисов, мобильных приложений, статьи и презентации от наших разработчиков, анонсы проектов и многое другое.
Download Telegram
Жадный импорт
#backend #php

Разрабатывая веб-сервис для крупного застройщика, мы столкнулись с задачей импорта большого количества номенклатурных данных. Причем данные выгружались из различных корпоративных систем клиента и представляли собой файлы формата csv и xml.

Данные импорта содержали информацию об объектах застройки с подробными их характеристиками. Данные по каждому объекту перед сохранением в БД должны были проходить определенный препроцессинг в виде валидации, проверок существования справочной информации и определения операции вставки/изменения. Все стандартно.

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

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

«Хватит это терпеть», — сказал разработчик Илья и призвал на помощь генераторы. Их использование позволило избавиться от промежуточных накоплений и обрабатывать данные построчно на лету. Весь процесс импорта после внедрения генераторов стал занимать практически константное значение потребляемой RAM.

Наш псевдокод немного преобразился. Стоит отметить, что использование генераторов делает код чище и позволяет работать с нативными итераторами в PHP.
​​React: профилирование жизненного цикла
#frontend #reactjs

Среди React-разработчиков популярно браузерное расширение React DevTools, позволяющее отлаживать клиентскую часть React-приложения. Это расширение содержит полезный инструмент профилирования, который нативно поддерживается самой библиотекой React, начиная с версии 16.5.

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

Рассмотрим пример уровня кода. В функциональный компонент SomeList передается объект с данными состояния dataSource из родительского компонента App. SomeList содержит дочерний компонент SomeItem, который оперирует переданным ему dataSource-объектом. При обновлении состояния в компоненте App, даже если сам объект dataSource не изменился, производится цепной ререндер нижестоящих компонентов SomeList и SomeItem, которые отслеживают dataSource. В данном случае обновление этих компонентов является избыточным.

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

В текущем примере для оптимизации повторного рендеринга компонентов применим механизм мемоизации, представленный в HOC React.memo(...). Теперь запустим профилировщик и почувствуем разницу.

На Reactjs.org есть отличное введение, которого будет достаточно для базовой проверки своих проектов.
Алина и Тайный Санта
#algorithms #math #jokes

Посвящается нашему офис-менеджеру Алине

Новогодние поздравления в Студии проходят по принципу церемонии Тайного Санты. Как же офис-менеджеру Алине организовать этот процесс, сохраняя максимальную анонимность, при условии что в Студии работает 100+ человек? 😱

Каждый сотрудник должен получить адресованный ему подарок, иначе на общем вручении выйдет конфуз.

Алина берет список всех сотрудников у HR Дарьи и садится за разработку алгоритма (идет к старшему разработчику Александру).

Чтобы организовать случайность пар «дарящий — получатель», список сотрудников перемешивается и помещается в массив L1. Затем элементы множества L1 циклически смещаются в любую сторону на число, не равное length(L1), и записываются в новый массив L2.

Теперь в L1[i] находится отправитель подарка для получателя L2[i]. Читателю должно быть очевидно 😂, что получившееся отображение f: L1 -> L2 биективно, а потому подарки достанутся всем. 🎁

Пары получены, но наша Алина делала все вручную, и теперь она знает все «тайны» и, что самое обидное, знает, кто подарит подарок именно ей. Исправим это с помощью HR Дарьи.

Даша и Алина делят список L1 на L11 и L12 таким образом, что Даша находится в одном списке, а Алина — в другом. Каждая из девочек выбирает себе половину списка, в котором нет ее фамилии/имени. Повторим процедуру перемешивания и сдвижки для списков L1j, сохраняя список со сдвигом в L2j. Теперь в L1j[i] находится отправитель подарка для L2j[i], где j = 1,2. Очевидно, что полученные отображения f1j: L1j -> L2j также биективны. Все учтено при полной секретности. 😎

З.Ы. Реализацию алгоритма оставим на усмотрение любопытного читателя. С наступающим Новым годом и Рождеством! 🎄
Контент — это мы
#backend #frontend #qa #mobile

Авторы заметок канала Chulakov Dev — это реальные люди, лучшие специалисты Студии №1 в России.

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

Команда Студии Олега Чулакова поздравляет вас с Новым годом и Рождеством. В наступившем 2020 году мы продолжим публикации и постараемся сделать их еще интереснее.
Отлично, оптимизируем дальше
#backend #php #orm

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

Первоначально, в пострелизный период, сервис хранил и обрабатывал около 300 квартир с сопутствующими номенклатурными данными. Для обеспечения реактивности интерфейсов и удобства вывода данные о сущностях и их атрибутах собирались в единую структуру. Это позволяло достаточно быстро перестраивать клиентский вывод без дополнительных REST-запросов, при этом фильтруя и сортируя данные.

Сервис развивался, и в какой-то момент нам выгрузили 1200 квартир. С учетом всех реляций количество связанных объектов стало достаточно большим — на одну квартиру приходилось около 12 связанных объектов с нетривиальной выборкой через ActiveRecord-модели. Конечный набор json-данных стал формироваться за 4 секунды.

«Хватит это терпеть», — сказал разработчик Илья и принялся оптимизировать, вооружившись профайлером и литром пива. Исходные данные профайлера: 4 секунды, 64 Мб памяти и более 140 запросов в БД. Используя эти данные, мы добавили недостающие индексы по ключам на уровне СУБД, а самое главное — мы оптимизировали реляции в ActiveRecord-моделях и сократили количество запросов к БД. После первой итерации профайлер показал следующее: 3 секунды, 32 Мб памяти и 80 запросов в БД.

Для того чтобы выборки одних и тех же данных не дублировались для каждой квартиры, все справочные данные были вынесены в отдельные запросы для единоразового выполнения.

После этой итерации мы получили следующие результаты: 1,5 секунды исполнения, 24 Мб и 54 запроса. Профайлер показал, что бОльшая часть времени тратится на манипуляции с ActiveRecord-моделями — инициализация и маппинг данных в объекты.

«Не на массивах же все это делать»

На последнем этапе оптимизации мы отказались от использования ORM. ActiveRecord-модели были заменены на заполнение простых DTO-объектов. Общение с БД и выборку данных мы реализовали через построитель запросов фреймворка Yii. Финальный результат: 0,4 секунды, 18 Мб памяти и около 32 запросов в БД.
​​ViewPager2. Подглядываем красиво
#mobile_native #android #java

20 ноября 2019 года вышла в релиз стабильная версия нового инструмента для пошагового показа экранов в ОС Android — ViewPager2. Переход с первой версии облегчается преемственностью синтаксиса ViewPager. Также новый компонент использует адаптеры на основе абстрактных классов RecyclerView.Adapter или FragmentStateAdapter при работе с фрагментом.

Произведем инициализацию ViewPager2 таким образом, чтобы были видны половинки предыдущей и последующей страниц.

Реализуем свой адаптер и сверстаем элемент, используемый в нем. YourAdapter готов к работе.

Реализацию фрагмента, содержащего ViewPager2, можно посмотреть здесь.

Необходимо заставить объект viewPager игнорировать padding-ограничения. За это отвечают строки 14 и 15 класса YourFragment.java.

В качестве объекта-трансформера страницы мы устанавливаем экземпляр класса YourPagerTransformer, который позволяет показывать часть левого и правого элемента списка при скролле.

Если ширина экрана WIDTH пикселей, а контент в layout/item.xml занимает x пикселей, то величина marginPx, которая будет передаваться в YourPagerTransformer, должна находиться в пределах WIDTH - x < marginPx < (WIDTH - x) / 2, чтобы левый и правый элемент были видны. Иначе они сдвинутся недостаточно далеко, чтобы показаться, или наложатся друг на друга.

Стоит отметить, что с помощью различных реализаций PageTransformer можно применять разные эффекты прокрутки.
Простая UI-локализация
#mobile_dev #ios #swift

Apple Xcode позволяет локализовывать интерфейсные статические текстовые метки, ресурсы приложения — иконки, изображения, звуковые файлы и форматы вывода даты/время/валюты/единиц измерения.

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

Первым делом в Xcode создается файл Localizable.strings, который на уровне проекта является агрегацией файлов с переводами текстовых меток на различные языки. А на уровне файловой системы для каждого языка будет создана папка <LocaleId>.lproj и файл Localizable.strings в ней.

В составе фреймворка Foundation для локализации строк предусмотрена глобальная функция NSLocalizedString.

Функция NSLocalizedString под капотом вызывает метод localizedStringForKey:value:table: объекта Bundle приложения, который возвращает локализованную строку.

Упростим себе жизнь. Чаще всего фразы переводов в рамках одного источника ресурсов можно хранить в одной таблице. Тогда можно создать свою функцию-обертку local, которая получает только параметр key.

Файлы Localizable.strings содержат пары «"ключ" = "значение"», где ключом выступает параметр, переданный нашей функции local(), а значением — языковая вариация строки.

Например, этот код демонстрирует процесс получения значений заголовка, сообщения и текста кнопки для системного алерта.
Языковые фразы, например, для русской локализации будут извлечены из этого файла.
Алло, мы ищем таланты!
#job #frontend #react #redux

Если ты уверенный Frontend Developer и не понаслышке знаешь про React.js + Redux, а также работаешь с Next.js, то ты именно тот человек, который нам нужен.

Сегодня мы ищем сразу несколько супергероев:
Middle Frontend Developer в наш московский офис для работы над проектом крупнейшего банка, в офисе клиента (блек-джек, штаб-квартира и daily cash прилагаются);
Middle+ или Senior Frontend Developer в главный ростовский офис для управления командами разработчиков и работой над лучшими проектами страны.

Звони или пиши нам:
+7 863 303-61-91
hr@chulakov.ru
https://vk.com/olegchulakovstudio
https://www.instagram.com/chulakov.ru

Ты нужен нам, а мы — тебе 😎
​​Сюрпризы с UITableView
#mobile_dev #ios #swift

С помощью стандартного табличного класса UITableView из UIKit часто необходимо показать алерт-сообщение по тапу на определенную ячейку.

Если у ячейки таблицы установлен cell.selectionStyle = .none, то желаемый алерт будет отображен с заметной задержкой. Баг воспроизводится с iOS 8.1 и до сих пор не исправлен.

Избавиться от такого странного поведения можно, обернув код вывода алерта в dispatch-блок так или так.

При использовании других значений для свойства selectionStyle проблема не воспроизводится.
​​QR на службе у QA
#frontend #qa

Любой веб-разработчик/тестировщик сталкивается с проблемой ввода URL в адресную строку различных мобильных устройств.

Как просматривать многостраничник на трех десктопах и пяти мобильных устройствах и не сойти с ума?

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

Мы решаем эту проблему, используя автогенерацию QR-кодов. Для браузера Google Chrome существует полезное расширение, шифрующее ссылку текущей страницы в QR-код. Далее с помощью любого мобильного устройства сканируем этот код, и вуаля — мы на нужной странице.

Мобильные устройства Apple, начиная с версии iOS 11, нативно имеют встроенный QR-ридер в приложении «Камера». Для Android-устройств используем сторонние приложения из Google Play.

С помощью QR-кодов можно шифровать не только ссылки для перехода, но и текстовые заметки, легко передавая их между устройствами.

Рекомендуем к использованию!
Веб тестируй без труда, на любых устройствах
#qa #frontend

Браузеры на основе Chromium по праву считаются лидерами по числу активных пользователей. Технологии этой платформы применяются даже для создания кроссплатформенных десктопных приложений, например, на фреймворке Electron.

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

Некоторые QA-специалисты Студии работают в офисе клиента над LTS-продуктами, иногда в другом городе. В таких условиях передача или перевозка физических устройств для тестирования веб-сервисов невозможны.

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

Для того чтобы взаимодействовать с локально развернутыми в тестовом окружении веб-сайтами, облачные сервисы позволяют устанавливать VPN-подобное соединение посредством специального клиентского софта.

Примерами таких SaaS являются BrowserStack, Sauce Labs, LambdaTest. Множество сервисов и конкурентная среда удерживают цены на достаточно демократичном уровне, что позволяет сэкономить в краткосрочной перспективе деньги на физических устройствах.
Ты видишь LS? — Вот и я не вижу, а он есть!
#qa #frontend

Разработка frontend-части веб-сервиса на основе интерактивных макетов упрощает жизнь верстальщику, позволяя более гибко работать с примитивами. При этом можно столкнуться с некоторыми неочевидными проблемами.

Например, при копировании текста из Sketch-макета и вставке его в верстку встречается «невидимый» символ U+2028. Line Separator реализует перенос последующего за ним текста на новую строку, однако его интерпретация и поведение в обозревателе могут зависеть и от браузера, и от операционной системы. Более того, не все редакторы кода подсвечивают этот символ.

Так, при просмотре верстки в Google Chrome такие символы будут отображаться пользователю как [LSEP] в ОС Windows 10 и [x] в ОС Android. В то время как пользователям MacOS и Windows 7 с применением любых браузеров они просто не видны.

Мы решаем эту проблему с помощью линтера, заменяя или подсвечивая нежелательные символы в коде. Такие символы также идентифицируются при просмотре DOM в Chrome DevTools и отображаются в виде красной точки.
Что за ссылка такая — ref?
#frontend #react

На собеседованиях мы обычно спрашиваем соискателя, что такое ref в React. Ответ часто таков: «Ref — это ссылка на DOM-узел». Такое определение необратимо устарело с выходом React v16.3.0. Именно в этой версии появилось API для создания объекта ref — React.createRef().

Получение ссылки на DOM-элемент — это всего лишь один из способов использования ref в React API. В более старых версиях React можно встретить методы refs callback для решения данной задачи.

Путаница с рефами стала более очевидной с приходом React Hooks. При изменении состояния функционального компонента может понадобиться не вызывать его повторный рендер. И это задача для рефов!

Например, нам необходимо остановить таймеры, проинициализированные функциями setTimeout или setInterval по клику на кнопку. Использование React.useState() избыточно для решения такой задачи и может ввести в заблуждение других разработчиков.

Из-за большого количества вопросов и issues на GitHub в официальной документации к React Hooks появился подобный вопрос: есть ли что-то вроде переменных экземпляра?https://ru.reactjs.org/docs/hooks-faq.html#is-there-something-like-instance-variables.

Мы рекомендуем именно такое определение: «ref — это объект, а его изменяемое свойство current может хранить в себе любое значение».
Проявляем смеCALCу в препроцессорах
#frontend #css #stylus #sass #less

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

Чистый CSS позволяет делать это без проблем — обращение к переменной производится путем вызова функции var():
--offset: 16px;
.block {
width: calc(100% - var(--offset));
}

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

В SASS для вызова из calc() переменную нужно обернуть в #{ }:
$offset: 16px;
.block {
width: calc(100% - #{$offset});
}

В Less это делается похожим образом, но строка с calc() экранируется:
@offset: 16px;
.block {
width: ~"calc(100% - @{offset})";
}

В Stylus синтаксис чуть сложнее:
$offset = 16px;
.block {
width "calc(100% - %s)" % $offset
}

Если необходимо использовать несколько переменных, Stylus позволяет делать так:
$breadth = 100%;
$offset = 16px;
.block {
width "calc(%s - %s)" % ($breadth $offset)
}
Babel + core-js = ❤️
#frontend #javascript #babel #corejs

Новые js-фичи часто опережают возможности браузеров. Для использования современных конструкций языка разработчикам приходится применять полифилы, настраивать сборщики, проверять поддержку различных методов.

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

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

На помощь приходит Babel. Пакет @babel/presset-env подключает необходимые модули библиотеки полифилов core-js, когда в коде используются не поддерживаемые браузерами языковые конструкции. Пресет ориентируется на список браузеров, указанный в package.json.

Чтобы Babel автоматически добавлял нужные полифилы в бандл, нужно создать в корне проекта babel.config.json. Такая конфигурация будет проверять пакеты из node_modules и добавлять полифилы core-js в соответствии с browserlist, указанном в package.json.

Вместо большого количества импортов и отказа от современных методов JavaScript можно добавить всего 14 строк в конфигурацию Babel. Подробнее о конфигурации Babel можно почитать здесь, о полифилах — тут.
Да грузись ты уже 😡
#qa #frontend

Уважающий себя веб-сервис с клиентской браузерной частью немыслим без наличия хорошо проработанной мобильной версии и адаптивности интерфейсов. Такое веб-приложение должно быстро и без сбоев работать в условиях мобильного интернета, с переменной скоростью соединения 3G/LTE-сетей.

Frontend-разработчики часто применяют принцип отложенной загрузки ресурсов для оптимизации скорости подачи контента и функционала пользователю. Сначала показывается только необходимый контент, а тяжелые ресурсы подгружаются асинхронно, в процессе взаимодействия с текущим интерфейсом. Например, когда пользователь сделает скролл до нужного блока.

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

Представим, что основной скрипт main.js пытается вызвать методы some-library-script.js, которые загружаются асинхронно. Без проверки доступности методов библиотеки или события, срабатывающего на ее загрузку в main.js, пользователь потеряет необходимый ему функционал и не решит свою целевую задачу.

Чем выше скорость интернета — тем больше шансов упустить заветную ошибку.

Начинающий разработчик может неверно реализовать динамическую подгрузку ресурсов, а QA-инженер должен об этом помнить и считать каждого разработчика начинающим 😂

Узнать, как правильно организовать асинхронность загрузки ресурсов, вам помогут полезные ссылки ниже 👇

Lazy Loading Images and Video
Скрипты: async, defer
Dynamic imports
Ошибки быть не должно!
#frontend #react #nextjs

Когда пользователь взаимодействует с веб-ресурсом, помимо ожидаемого результата, он может наблюдать специальные страницы, отображающие нештатные ситуации в виде http-исключений. Разрабатывая сервисы на Next.js, необходимо управлять выводом таких страниц, анализируя ответы от RESTful API. А с учетом технологии SSR обработчик должен уметь изменять Status Code при отдаче страницы с сервера.

Коробочное решение фреймворка позволяет обработать 404 и 500 http-статусы и кастомизировать вывод страниц для них. При этом обработчик не учитывает случай, когда скрипт страницы загружен, а метод API вернул статус >= 400.

Мы решили отказаться от стандартного способа перехвата и обработки http-исключений в пользу собственного хелпера handleResponseStatus.js.

В хелпере мы учли возможность добавления «глобальных» запросов, таких как авторизация, и «параллельных» запросов, например загрузки меню сайта. Эту задачу решает callback-функция requestFunction, которая возвращает Promise.all. В теле колбека можно контролировать последовательность выполнения с помощью async/await, а в Promise.all — добавлять параллельные запросы.

Осталось привести пример использования хелпера в _app.js и поделиться полезными ссылками 👇

NextJS | getInitialProps
NextJS | Custom Error
ReactDOMServer
Вооружен и опасен
#qa #frontend

В процессе тестирования наши QA-инженеры активно применяют различные инструменты. В их число входят и расширения для популярных браузеров. В этой заметке мы рассказали про плагин генерации QR-кодов, а сейчас поделимся и некоторыми другими.

PerfectPixelпозволяет накладывать изображение поверх открытого сайта, регулировать масштаб картинки, позицию и степень прозрачности. Используется по назначению — для максимально точного сравнения макета сайта с его сверстанной версией. В Студии его применяют как QA, так и разработчики.
Chrome | Safari | Firefox | Opera | IE | Edge

Form Filler — автоматически заполняет все формы на странице случайными данными, умеет работать с радиокнопками, выпадашками, понимает типы полей. Спасательный круг для тех, кто тонет в тестировании форм, имеет открытый исходный код.
Chrome | Edge | Firefox

WhatFont — при клике на текст отрисовывает в этом месте плашку со всей информацией о его шрифте. Пользоваться расширением быстрее и нагляднее, чем инструментами разработчика.
Chrome | Safari

Full Page Screen Capture — по нажатии кнопки создает высококачественный скриншот всей страницы, старается учитывать все плавающие элементы в верстке, например шапку. Есть экспорт в .pdf и редактор в платной версии.
Chrome

ProKeys — для тех, кто любит много писать. Добавляет в браузер автокомплит текста при вводе кавычек и скобок, как в IDE. Умеет разворачивать любое кодовое слово в произвольный текст на основе шаблона — с поддержкой автоподстановки дат, контента из буфера обмена и быстрой навигацией по маркерам в шаблоне. Расширение полностью настраиваемое и имеет открытый исходный код.
Chrome | Opera

Check My Links — проходится по всем ссылкам на странице и проверяет их на валидность. Результат подсвечивается цветом прямо в верстке, есть базовый вывод в лог консоли и возможность экспорта детального отчета в CSV.
Chrome

JSONViewрасширение форматирует открытый в адресной строке JSON-файл в читабельный и удобный для навигации вид и валидирует его. Полезен при тестировании ответов от RESTful API.
Chrome

Bug Magnet — полезный инструмент для проведения исследовательского тестирования форм. Представляет собой набор «плохих», длинных или необычных фраз, невидимых символов, нестандартных языков, текстовых эксплоитов и далее по списку — все то, что потенциально может сломать отправку формы на сайте. Есть возможность расширять базу своими заготовками.
Chrome | Firefox

З.Ы. Устанавливайте любые расширения браузера осознанно. Говорят, что некоторые из них могут использовать ваши личные данные и майнить биткоины на ваших машинах 😎 Но это не точно 😉
​​Опасная высота
#qa #frontend

Создавая макеты мобильного адаптива, обычно ориентируются на самые маленькие экраны шириной в 320 px, например как у Apple iPhone 5s. При этом высоту экрана рассчитывают с точки зрения необходимости размещения законченного целостного блока на одном экране и визуального индикатора присутствия скролла «Скролльте вниз».

Здесь может произойти неочевидная подмена характеристик: screen size — размер физического экрана и viewport size — размер его контентной части в окне мобильного браузера.

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

Высота viewport-области может меняться даже в рамках одного устройства — при использовании различных браузеров. Более того, она может меняться в процессе навигации по сайту. Например, браузер iOS Safari уменьшает свою панель навигации при скролле вниз, из-за чего могут ложно срабатывать некоторые js-события, отслеживающие ресайз.

Дадим несколько советов, призванных помочь вам в борьбе за функциональность и красоту адаптивов 😉

1. Используйте динамическое позиционирование элемента относительно высоты текущего viewport. Например, блока с иконкой «Скролльте вниз».
2. При тестировании веб-интерфейса создавайте свои шаблоны мобильных устройств в браузерных инструментах с уменьшенной высотой по отношению к стандартным. Например, на 80—100 px меньше.
3. Проверяйте работу интерфейса на реальных устройствах или полноценных симуляторах. Например, Xcode Simulator для iOS.
4. И конечно, учитывайте высоту viewport-области в макетах дизайна.
Друзья, мы хотим, чтобы наши заметки приносили 100% пользы. Поэтому сегодня мы хотим познакомиться с вами — так мы сможем сделать контент еще более интересным и индивидуальным для каждого. Пожалуйста, не стесняйтесь и нажимайте на подходящий вариант👇
Anonymous Poll
40%
Web Frontend Developer
8%
Web Backend Developer
25%
Web Full stack Developer
1%
iOS SWE
2%
Android SWE
2%
Mobile Full stack Developer
2%
QA Engineer
15%
Мне просто интересна разработка
7%
Я инопланетянин и залетел не туда
Продолжаем знакомиться с нашими подписчиками. Все знают, что главный офис Студии, он же лучший digital-офис России, находится в Ростове-на-Дону. Еще у нас есть филиал в Москве.

Опрос: А в каком городе вы живете?
Anonymous Poll
23%
Москва
6%
Санкт-Петербург
2%
Новосибирск
2%
Екатеринбург
1%
Нижний Новгород
3%
Казань
2%
Челябинск
2%
Омск
18%
Ростов-на-Дону
42%
Другой