Время лечит
Как правильно сделать анимацию линий на графике или полет снаряда в игре, чтобы на всех устройствах скорость была одинаковой?
В примерах даже от таких библиотек, как PixiJS, можно встретить неправильный код: размер или позиция элемента меняются на определенную величину при каждом тике — колбэке setInterval или requestAnimationFrame. Это упрощенные примеры, и важно не перенести такое же поведение в production.
Использование setInterval приведет к тормозам на слабых устройствах. Может не хватить ресурсов для отрисовки каждые N миллисекунд.
Движение на фиксированную величину при каждом requestAnimationFrame приведет к разной скорости. На мощных устройствах requestAnimationFrame будет срабатывать часто и скорость анимации будет большой, а на слабых — наоборот. В зависимости от производительности и нагрузки, у одних пользователей объект может двигаться на пиксель каждые 15 мс, а в других — только 2 раза в секунду.
Решение — работать со временем. Если мы знаем, что за секунду элемент должен сдвинуться на 100 пикселей, а с момента прошлого вызова прошло полсекунды, то нужно сместить объект на 50 пикселей. Все просто.
Как правильно сделать анимацию линий на графике или полет снаряда в игре, чтобы на всех устройствах скорость была одинаковой?
В примерах даже от таких библиотек, как PixiJS, можно встретить неправильный код: размер или позиция элемента меняются на определенную величину при каждом тике — колбэке setInterval или requestAnimationFrame. Это упрощенные примеры, и важно не перенести такое же поведение в production.
Использование setInterval приведет к тормозам на слабых устройствах. Может не хватить ресурсов для отрисовки каждые N миллисекунд.
Движение на фиксированную величину при каждом requestAnimationFrame приведет к разной скорости. На мощных устройствах requestAnimationFrame будет срабатывать часто и скорость анимации будет большой, а на слабых — наоборот. В зависимости от производительности и нагрузки, у одних пользователей объект может двигаться на пиксель каждые 15 мс, а в других — только 2 раза в секунду.
Решение — работать со временем. Если мы знаем, что за секунду элемент должен сдвинуться на 100 пикселей, а с момента прошлого вызова прошло полсекунды, то нужно сместить объект на 50 пикселей. Все просто.
Разошлись во времени
Несколько мелочей в дополнение к прошлой заметке:
1. Чтобы избежать обрыва анимации при возникновении ошибки в коде, стоит разместить вызов
2. Для расчета дельты можно использовать временную метку, которую
3. Многие библиотеки для 2D- и 3D-графики вычисляют дельту самостоятельно. Примеры: PixiJS и ThreeJS.
Несколько мелочей в дополнение к прошлой заметке:
1. Чтобы избежать обрыва анимации при возникновении ошибки в коде, стоит разместить вызов
requestAnimationFrame в начале колбэка.2. Для расчета дельты можно использовать временную метку, которую
requestAnimationFrame передает аргументом в колбэк. Она есть и в популярных полифилах вроде raf, где вычисляется на основе performance.now() или Date.now().3. Многие библиотеки для 2D- и 3D-графики вычисляют дельту самостоятельно. Примеры: PixiJS и ThreeJS.
Выполнять!
Что делать, если нужно выполнить php-скрипт, содержащий команду, которая запрещена в конфигурации? Даже если есть доступ к
Одним из решений является запуск нужного скрипта в командной строке c добавлением аргумента
Таким образом, чтобы разблокировать для скрипта все php-функции, можно использовать команду:
Что делать, если нужно выполнить php-скрипт, содержащий команду, которая запрещена в конфигурации? Даже если есть доступ к
php.ini, включение функций вроде exec может привести к угрозам безопасности сервера.Одним из решений является запуск нужного скрипта в командной строке c добавлением аргумента
-d. Значения перечисленных в нем параметров будут заменены указанными в команде. Остальные параметры будут соответствовать php.ini.Таким образом, чтобы разблокировать для скрипта все php-функции, можно использовать команду:
php -d disable_functions="" noscript.phpДавай сам
В этой заметке расскажем, как организовать Docker-архитектуру, которая сама узнает о новых контейнерах с web-приложениями и опубликует их.
Для доступа к приложениям из внешней среды используется контейнер с прокси-сервером на основе nginx. Он является единственным в Docker-окружении доступным внешней среде по портам 80 (http) и 443 (https). В зависимости от запрашиваемого доменного имени nginx проксирует запрос на соответствующий backend-сервис внутри Docker-сети.
Backend-сервис — это контейнер с web-приложением, принимающий запросы на 80-й порт от nginx. Таких контейнеров в окружении может быть много, и их количество будет расти с релизами новых web-сайтов и сервисов.
Автоматизировать деплоймент новых контейнеров с web-приложениями можно с помощью сервиса на основе образа nginx-proxy.
При добавлении нового сайта нужно обновить конфигурацию nginx и сделать reload. Чтобы не делать этого вручную, избежать ошибок и не тратить время специалистов, используем docker-gen, который уже встроен в образ nginx-proxy.
Контейнер nginx-proxy реализует функцию Service Discovery в нашей Docker-сети, реагируя на регистрацию новых или остановку существующих Docker-контейнеров. Управлением сервисами внутри контейнера с nginx и docker-gen занимается менеджер процессов forego.
Для того чтобы nginx-сервис замечал изменения в окружении, необходимо запускать контейнеры с environment-константой
В этой заметке расскажем, как организовать Docker-архитектуру, которая сама узнает о новых контейнерах с web-приложениями и опубликует их.
Для доступа к приложениям из внешней среды используется контейнер с прокси-сервером на основе nginx. Он является единственным в Docker-окружении доступным внешней среде по портам 80 (http) и 443 (https). В зависимости от запрашиваемого доменного имени nginx проксирует запрос на соответствующий backend-сервис внутри Docker-сети.
Backend-сервис — это контейнер с web-приложением, принимающий запросы на 80-й порт от nginx. Таких контейнеров в окружении может быть много, и их количество будет расти с релизами новых web-сайтов и сервисов.
Автоматизировать деплоймент новых контейнеров с web-приложениями можно с помощью сервиса на основе образа nginx-proxy.
При добавлении нового сайта нужно обновить конфигурацию nginx и сделать reload. Чтобы не делать этого вручную, избежать ошибок и не тратить время специалистов, используем docker-gen, который уже встроен в образ nginx-proxy.
Контейнер nginx-proxy реализует функцию Service Discovery в нашей Docker-сети, реагируя на регистрацию новых или остановку существующих Docker-контейнеров. Управлением сервисами внутри контейнера с nginx и docker-gen занимается менеджер процессов forego.
Для того чтобы nginx-сервис замечал изменения в окружении, необходимо запускать контейнеры с environment-константой
VIRTUAL_HOST. Значением этой константы будет доменное имя web-приложения, для которого произойдет автоматическая настройка проксирования http(s)-запросов.Защищайся
Месяц назад мы рассказали про важность SSL-сертификатов для современных сайтов и сервисов.
Давайте рассмотрим решение, которое позволит автоматизировать процесс получения бесплатных сертификатов в рамках Docker-архитектуры, описанной в прошлой заметке.
Нам понадобится сервис letsencrypt-nginx-proxy-companion, который является компаньоном к nginx-proxy и уже умеет с ним взаимодействовать.
Контейнер letsencrypt-nginx-proxy-companion автоматически генерирует новые и обновляет существующие сертификаты, а также дает знать об этом nginx-proxy. Таким образом, для web-приложений, требующих SSL, автоматически изменяются конфигурационные файлы для проксирующего nginx-сервера.
Чтобы сгенерировать сертификат, нам необходимо добавить две константы окружения для команды запуска Docker-контейнера:
1.
2.
Месяц назад мы рассказали про важность SSL-сертификатов для современных сайтов и сервисов.
Давайте рассмотрим решение, которое позволит автоматизировать процесс получения бесплатных сертификатов в рамках Docker-архитектуры, описанной в прошлой заметке.
Нам понадобится сервис letsencrypt-nginx-proxy-companion, который является компаньоном к nginx-proxy и уже умеет с ним взаимодействовать.
Контейнер letsencrypt-nginx-proxy-companion автоматически генерирует новые и обновляет существующие сертификаты, а также дает знать об этом nginx-proxy. Таким образом, для web-приложений, требующих SSL, автоматически изменяются конфигурационные файлы для проксирующего nginx-сервера.
Чтобы сгенерировать сертификат, нам необходимо добавить две константы окружения для команды запуска Docker-контейнера:
1.
LETSENCRYPT_HOST — список доменных имен, для которых нужно получить SSL-сертификат.2.
LETSENCRYPT_EMAIL — email для регистрации в Let’s Encrypt.Вы не ответили на мой запрос
Политика безопасности браузеров не позволяет делать AJAX-запросы на другие домены без разрешения от сервера, на который эти запросы поступают.
Но если сервер вернет в ответе специальные заголовки, то кросс-доменный запрос выполнится успешно.
Примеры добавления заголовков на стороне различных веб-серверов и фреймворков:
https://bitbucket.org/snippets/OlegChulakovStudio/reEKM5
Если на стороне frontend требуется работа с сессией, то при отправке запроса нужно активировать флаг
https://bitbucket.org/snippets/OlegChulakovStudio/ye7pRa
Политика безопасности браузеров не позволяет делать AJAX-запросы на другие домены без разрешения от сервера, на который эти запросы поступают.
Но если сервер вернет в ответе специальные заголовки, то кросс-доменный запрос выполнится успешно.
Примеры добавления заголовков на стороне различных веб-серверов и фреймворков:
https://bitbucket.org/snippets/OlegChulakovStudio/reEKM5
Если на стороне frontend требуется работа с сессией, то при отправке запроса нужно активировать флаг
withCredentials, который позволит работать с cookie: https://bitbucket.org/snippets/OlegChulakovStudio/ye7pRa
Погоди
Во многих сервисах пользователям приходится заполнять формы с большим количеством полей. И чем их больше, тем больнее терять введенные данные.
Чтобы спасти пользователя от такой досадной неудачи, обычно используют блокировку перехода и открывают модальное окно с вопросом о подтверждении намерений.
Чтобы реализовать это на стеке React, Redux, React Router 4, можно воспользоваться методом
Используя наработки из заметок про формы и модальные окна в React, мы собрали новое интерактивное демо с кодом решения:
https://codesandbox.io/s/zlp6zwkr3p
Если перейти к форме, начать ее заполнять, а затем попытаться покинуть страницу, то приложение поможет предотвратить потерю введенных данных.
Во многих сервисах пользователям приходится заполнять формы с большим количеством полей. И чем их больше, тем больнее терять введенные данные.
Чтобы спасти пользователя от такой досадной неудачи, обычно используют блокировку перехода и открывают модальное окно с вопросом о подтверждении намерений.
Чтобы реализовать это на стеке React, Redux, React Router 4, можно воспользоваться методом
block объекта history, который получают из компонента высшего порядка withRouter. Вызвать его нужно в методе жизненного цикла componentWillUnmount.Используя наработки из заметок про формы и модальные окна в React, мы собрали новое интерактивное демо с кодом решения:
https://codesandbox.io/s/zlp6zwkr3p
Если перейти к форме, начать ее заполнять, а затем попытаться покинуть страницу, то приложение поможет предотвратить потерю введенных данных.
Игра Сервера
Для управления конфигурациями на удаленных машинах мы используем Ansible. Чтобы начать его применять, достаточно:
1) установить Ansible на локальной машине;
2) открыть доступ по SSH-ключу на нужные хосты;
3) на декларативном языке в формате YAML описать задачи, которые необходимо выполнить на хостовых машинах.
В Ansible есть много модулей для установки ПО, выполнения консольных команд, управления пользователями, файловой системой и сетевой инфраструктурой. Также есть поддержка Docker для работы с образами, контейнерами и сервисами.
Рассмотрим пример, в котором необходимо установить инфраструктуру для web-окружения: nginx, Apache, PHP, MySQL. У нас имеются Docker-сервисы, описанные в docker-compose:
https://bitbucket.org/snippets/OlegChulakovStudio/Bez6q5
Напишем конфигурацию Ansible, которая позволит запустить эти сервисы на удаленных машинах.
Сначала сформируем задачи:
1) создать на удаленной машине директорию, в которую мы поместим наш файл
2) скопировать в эту директорию файл
3) запустить сервисы из
Получим такую конфигурацию:
https://bitbucket.org/snippets/OlegChulakovStudio/ke7KBb
Для ее запуска необходимо выполнить команду:
Для управления конфигурациями на удаленных машинах мы используем Ansible. Чтобы начать его применять, достаточно:
1) установить Ansible на локальной машине;
2) открыть доступ по SSH-ключу на нужные хосты;
3) на декларативном языке в формате YAML описать задачи, которые необходимо выполнить на хостовых машинах.
В Ansible есть много модулей для установки ПО, выполнения консольных команд, управления пользователями, файловой системой и сетевой инфраструктурой. Также есть поддержка Docker для работы с образами, контейнерами и сервисами.
Рассмотрим пример, в котором необходимо установить инфраструктуру для web-окружения: nginx, Apache, PHP, MySQL. У нас имеются Docker-сервисы, описанные в docker-compose:
https://bitbucket.org/snippets/OlegChulakovStudio/Bez6q5
Напишем конфигурацию Ansible, которая позволит запустить эти сервисы на удаленных машинах.
Сначала сформируем задачи:
1) создать на удаленной машине директорию, в которую мы поместим наш файл
docker-compose.yml;2) скопировать в эту директорию файл
docker-compose.yml;3) запустить сервисы из
docker-compose.Получим такую конфигурацию:
https://bitbucket.org/snippets/OlegChulakovStudio/ke7KBb
Для ее запуска необходимо выполнить команду:
ansible-playbook ./install.yml -i example.host.comДавай плавнее
Все, кто занимается созданием анимаций, знают про функции плавности (easing) и помнят, как работают основные.
Иногда приходится делать необычные анимации, которых не добиться популярными функциями плавности. Взять, к примеру, появление заголовка на главной странице bakucitycircuit.com — каждый символ заголовка появляется из прозрачности с эффектом включения люминесцентной лампы.
Эту задачу мы решили с помощью GSAP и плагина CustomEase. В коде эта анимация выглядит как обычный
Все, кто занимается созданием анимаций, знают про функции плавности (easing) и помнят, как работают основные.
Иногда приходится делать необычные анимации, которых не добиться популярными функциями плавности. Взять, к примеру, появление заголовка на главной странице bakucitycircuit.com — каждый символ заголовка появляется из прозрачности с эффектом включения люминесцентной лампы.
Эту задачу мы решили с помощью GSAP и плагина CustomEase. В коде эта анимация выглядит как обычный
fromTo от opacity:0 до opacity:1. Но для нее мы создали в конструкторе специальный easing, вычисленный в процессе неоднократного включения и выключения ламп в офисе Студии.Не с той стороны
Зачастую необходимо выполнить сортировку по полям, в которых могут присутствовать null-значения, и расположить результирующие строки с такими значениями либо в конце, либо в начале выборки.
Стандартное поведение в MySQL: если мы делаем
Предположим, у нас есть таблица
1. Попробуем отсортировать данные в порядке возрастания цены, при этом переместить строки с null-значениями в конец.
Обычная сортировка вернет null-значения в начале выборки:
Для того чтобы изменить такое поведение сортировки, можно воспользоваться одним из трюков:
2. Другая задача: нужно отсортировать выборку в порядке убывания цены, а строки с null-значениями разместить в начале.
По умолчанию после сортировки строки с null-значениями цен будут располагаться в конце выборки:
Для того чтобы получить нужный порядок, можно воспользоваться одним из следующих запросов:
Следует заметить, что при сортировке с помощью конструкции
Зачастую необходимо выполнить сортировку по полям, в которых могут присутствовать null-значения, и расположить результирующие строки с такими значениями либо в конце, либо в начале выборки.
Стандартное поведение в MySQL: если мы делаем
order by ASC, то строки с null-значениями сортируемого поля помещаются в начале выборки, если же делаем order by DESC — в конце.Предположим, у нас есть таблица
example со следующей структурой и содержимым:| id | price |
| 1 | 5 |
| 2 | 2 |
| 3 | null |
| 4 | 1 |
1. Попробуем отсортировать данные в порядке возрастания цены, при этом переместить строки с null-значениями в конец.
Обычная сортировка вернет null-значения в начале выборки:
SELECT * FROM example order by price ASC| id | price |
| 3 | null |
| 4 | 1 |
| 2 | 2 |
| 1 | 5 |
Для того чтобы изменить такое поведение сортировки, можно воспользоваться одним из трюков:
SELECT * FROM example order by -price DESCSELECT * FROM example order by ISNULL(price), price ASC| id | price |
| 4 | 1 |
| 2 | 2 |
| 1 | 5 |
| 3 | null |
2. Другая задача: нужно отсортировать выборку в порядке убывания цены, а строки с null-значениями разместить в начале.
По умолчанию после сортировки строки с null-значениями цен будут располагаться в конце выборки:
SELECT * FROM example order by price DESC| id | price |
| 1 | 5 |
| 2 | 2 |
| 4 | 1 |
| 3 | null |
Для того чтобы получить нужный порядок, можно воспользоваться одним из следующих запросов:
SELECT * FROM example order by -price ASCSELECT * FROM example order by ISNULL(price) DESC, price DESC| id | price |
| 3 | null |
| 1 | 5 |
| 2 | 2 |
| 4 | 1 |
Следует заметить, что при сортировке с помощью конструкции
order by -price индекс по полю price (если он есть) не будет задействован, тем самым время выборки может возрасти, а оптимальность плана выполнения запроса — снизиться.Я тебя запомнил
Чтобы ускорить загрузку web-страниц и сэкономить трафик, можно заставить браузер их кэшировать. Для этого необходимо правильно настроить заголовки ответа со стороны web-сервера.
Для этих целей предусмотрены заголовки Cache-Control, If-None-Match, If-Modified-Since, Last-Modified, ETag и другие. Также существует специальный HTTP-статус ответа
Допустим, браузер выполняет GET-запрос страницы chulakov.ru первый раз. Web-сервер формирует и возвращает контент страницы, в ответе отправляет заголовок
При повторном просмотре этой страницы браузер включит в запрос заголовок
Такой подход наиболее эффективен для конечного пользователя, если последний часто посещает одни и те же ресурсы, а информация на этих ресурсах меняется редко.
Кэширование контента web-страниц применимо к HTTP-запросам, не меняющим данные на сервере. Например, к GET-запросам.
Чтобы ускорить загрузку web-страниц и сэкономить трафик, можно заставить браузер их кэшировать. Для этого необходимо правильно настроить заголовки ответа со стороны web-сервера.
Для этих целей предусмотрены заголовки Cache-Control, If-None-Match, If-Modified-Since, Last-Modified, ETag и другие. Также существует специальный HTTP-статус ответа
304 Not Modified.Допустим, браузер выполняет GET-запрос страницы chulakov.ru первый раз. Web-сервер формирует и возвращает контент страницы, в ответе отправляет заголовок
Last-Modified: Sat, 13 Jan 2018 13:38:04 GMT, который содержит последнюю дату изменения запрашиваемого содержимого страницы.При повторном просмотре этой страницы браузер включит в запрос заголовок
If-Modified-Since: Sat, 13 Jan 2018 13:38:04 GMT. И если контент запрашиваемой страницы не был изменен после переданной даты, то сервер вернет HTTP-статус 304. Это послужит командой для браузера поднять страницу из кэша.Такой подход наиболее эффективен для конечного пользователя, если последний часто посещает одни и те же ресурсы, а информация на этих ресурсах меняется редко.
Кэширование контента web-страниц применимо к HTTP-запросам, не меняющим данные на сервере. Например, к GET-запросам.
Как вам будет удобно
Поддержка брендов часто включает в себя верстку писем, которые компании рассылают своим клиентам. При разработке сервисов могут потребоваться различные шаблоны email-оповещений. Но верстать письма никто не любит: в популярных почтовых клиентах не работает большинство CSS-свойств, а оставшиеся нужно писать непосредственно в атрибуте style у HTML-элементов. Такой код достаточно быстро становится нечитаемым. Соответственно, дорабатывать верстку письма будет значительно сложнее.
Любой неудобный процесс нужно автоматизировать. Для комфортной верстки писем мы сделали небольшой шаблон, использующий gulp-inline-css. С его помощью можно писать HTML и CSS раздельно, а HTML-файл со всеми стилями получать автоматически. Кроме того, чтобы написание CSS было максимально удобным, мы добавили в сборку препроцессор Stylus, который используем в большинстве проектов.
Таким образом, верстку писем можно сделать такой же привычной, как верстку сайта.
Поддержка брендов часто включает в себя верстку писем, которые компании рассылают своим клиентам. При разработке сервисов могут потребоваться различные шаблоны email-оповещений. Но верстать письма никто не любит: в популярных почтовых клиентах не работает большинство CSS-свойств, а оставшиеся нужно писать непосредственно в атрибуте style у HTML-элементов. Такой код достаточно быстро становится нечитаемым. Соответственно, дорабатывать верстку письма будет значительно сложнее.
Любой неудобный процесс нужно автоматизировать. Для комфортной верстки писем мы сделали небольшой шаблон, использующий gulp-inline-css. С его помощью можно писать HTML и CSS раздельно, а HTML-файл со всеми стилями получать автоматически. Кроме того, чтобы написание CSS было максимально удобным, мы добавили в сборку препроцессор Stylus, который используем в большинстве проектов.
Таким образом, верстку писем можно сделать такой же привычной, как верстку сайта.
По-моему, я тут уже был
Недавно мы писали про кэширование контента web-страниц, а сегодня поговорим о кэшировании статических файлов: JS, CSS, изображений, шрифтов и т.д.
При переходе по страницам сайта или повторном посещении большинство файлов, отвечающих за оформление страниц, уже должны быть у пользователя в кэше. Это положительно скажется на скорости загрузки и значительно снизит нагрузку на сервер.
Для того чтобы браузер закэшировал файл на необходимое время, используются заголовки Cache-control, Expires и Vary, которые сервер может прислать вместе с файлом.
Чтобы сбросить кэш браузера для этих файлов, нужно изменить URL-адрес либо с помощью GET-параметра (например,
Настроить кэширование статики несложно. Вот, например, конфигурация для nginx:
https://bitbucket.org/snippets/OlegChulakovStudio/qeLrEg
Недавно мы писали про кэширование контента web-страниц, а сегодня поговорим о кэшировании статических файлов: JS, CSS, изображений, шрифтов и т.д.
При переходе по страницам сайта или повторном посещении большинство файлов, отвечающих за оформление страниц, уже должны быть у пользователя в кэше. Это положительно скажется на скорости загрузки и значительно снизит нагрузку на сервер.
Для того чтобы браузер закэшировал файл на необходимое время, используются заголовки Cache-control, Expires и Vary, которые сервер может прислать вместе с файлом.
Чтобы сбросить кэш браузера для этих файлов, нужно изменить URL-адрес либо с помощью GET-параметра (например,
/js/noscript.js?v=2), либо изменив путь до самого файла, как это делает asset-менеджер Yii 2.Настроить кэширование статики несложно. Вот, например, конфигурация для nginx:
https://bitbucket.org/snippets/OlegChulakovStudio/qeLrEg
А так можно?
Недавно мы рассказали о нашем подходе к работе с CSS при верстке писем. Некоторые подписчики написали нам на ask@deep.digital вопросы о том, что можно использовать в письмах, а что — нет.
Если сделать акцент на том, что чаще всего используется верстальщиками или блокируется популярными почтовыми сервисами и программами, то можем дать следующие рекомендации.
Не использовать
Не использовать
Во многих почтовых клиентах не работает и
Не подключать SVG-изображения, шрифты, JS- и CSS-файлы. Если в тексте есть, например, заголовок, написанный нестандартным шрифтом, то лучше вставить его картинкой.
Не пользоваться в теле письма тэгами, кроме
Недавно мы рассказали о нашем подходе к работе с CSS при верстке писем. Некоторые подписчики написали нам на ask@deep.digital вопросы о том, что можно использовать в письмах, а что — нет.
Если сделать акцент на том, что чаще всего используется верстальщиками или блокируется популярными почтовыми сервисами и программами, то можем дать следующие рекомендации.
Не использовать
float и flex. Если нужно расположить элементы в строку, то, чтобы работало в Outlook, придется делать это с помощью таблиц.Не использовать
position, transform и отрицательные margin. Многие почтовые сервисы удаляют такие свойства, защищаясь от того, что контент письма может «залезть» на их интерфейс.Во многих почтовых клиентах не работает и
background-image. Это исправляется с помощью различных «костылей», но лучше к ним не прибегать и добавлять изображения с помощью тэга img.Не подключать SVG-изображения, шрифты, JS- и CSS-файлы. Если в тексте есть, например, заголовок, написанный нестандартным шрифтом, то лучше вставить его картинкой.
Не пользоваться в теле письма тэгами, кроме
div, span, a, table, tr, td, span, strong/b, em/i и img. Например, применение тэга p может привести к конфликту со стандартными стилями отступов этого элемента у почтового сервиса, а тэги вроде video, audio, form, input будут удалены или не будут выполнять свои функции.Все течет, все меняется
Кэширование на стороне браузера применимо и к динамическому контенту. Когда загружаемые данные web-страницы изменятся, кэш будет сброшен.
В одной из предыдущих заметок мы рассмотрели кэширование с применением заголовков Last-Modified и If-Modified-Since из спецификации HTTP 1.0.
В спецификации HTTP 1.1 появились более универсальные заголовки Etag и If-None-Match.
При первом запросе контента web-страницы браузеру возвращается заголовок
Вместе с заголовками
Кэширование на стороне браузера применимо и к динамическому контенту. Когда загружаемые данные web-страницы изменятся, кэш будет сброшен.
В одной из предыдущих заметок мы рассмотрели кэширование с применением заголовков Last-Modified и If-Modified-Since из спецификации HTTP 1.0.
В спецификации HTTP 1.1 появились более универсальные заголовки Etag и If-None-Match.
При первом запросе контента web-страницы браузеру возвращается заголовок
Etag с уникальным идентификатором ресурса в виде хеша. При последующих запросах этого же ресурса серверу передается уникальный хеш с помощью заголовка If-None-Match. Если контент ресурса не поменялся, то сервер вернет HTTP-статус 304 Not Modified и браузер отдаст контент из своего кэша. В противном случае сервер вернет обновленный контент со статусом 200 OK.Вместе с заголовками
Etag можно использовать заголовок Expires, в котором задается время максимального хранения кэша.Следите за выражениями
При составлении регулярных выражений мы часто пользуемся специальными сервисами и только потом переносим эти выражения в свой код.
Иногда даже проверенные регулярные выражения могут работать не так, как ожидалось. Конечно, большинство проблем решается с помощью применения флагов или дополнительного изучения справочной информации.
Но бывают случаи, когда локальные тесты проходят успешно, а при переносе на промышленные серверы поведение «регулярки» меняется не в лучшую сторону.
Работа с кириллицей может стать корнем проблем. Вот такое регулярное выражение отказалось работать с русскими буквами на промышленном сервере заказчика:
Изучив проблему, мы поняли, что в старых версиях PHP-модуля pcre стандартный перечень
Для того чтобы ваши регулярные выражения корректно работали с русскими символами, необходимо, чтобы версия
При составлении регулярных выражений мы часто пользуемся специальными сервисами и только потом переносим эти выражения в свой код.
Иногда даже проверенные регулярные выражения могут работать не так, как ожидалось. Конечно, большинство проблем решается с помощью применения флагов или дополнительного изучения справочной информации.
Но бывают случаи, когда локальные тесты проходят успешно, а при переносе на промышленные серверы поведение «регулярки» меняется не в лучшую сторону.
Работа с кириллицей может стать корнем проблем. Вот такое регулярное выражение отказалось работать с русскими буквами на промышленном сервере заказчика:
$string = preg_replace('/[^\d\w\s\.\:-]+/u', '', $string);Изучив проблему, мы поняли, что в старых версиях PHP-модуля pcre стандартный перечень
\w не охватывает кириллические символы даже с модификатором u. Именно этот модуль реализует работу Perl-совместимых регулярных выражений в PHP.Для того чтобы ваши регулярные выражения корректно работали с русскими символами, необходимо, чтобы версия
pcre была не ниже 8.38. Проверить это можно, выполнив консольную команду$ php -i | grep PCRE
Разметка? Нет, не слышали
Телеграм дает много возможностей для создания ботов. Часто их используют для публикации новостей в каналах. Публиковать свои сообщения очень просто: метод
Однако вместе с ним передается список объектов MessageEntity, в которых хранится тип, позиция и длины размеченных частей текста. Мы не нашли библиотек, которые могли бы формировать на основе этих данных, например, markdown-код. При этом любое внесение изменений в исходный текст приводит к несовпадению индексов у последующих MessageEntity. Если начать вставлять теги разметки, то текст начнет смещаться с позиций, указанных в MessageEntity, и будет размечаться не тот контент.
Как мы решили проблему?
Шаг 1: Собрать необходимые данные
Мы собрали все части в один список. В него попали входные и закрывающие индексы.
https://bitbucket.org/snippets/OlegChulakovStudio/Beok58
Шаг 2: Разрезать на части!
По существующим индексам мы порезали сообщение на части, начиная с конца. В результате получили маркированный список отрезков исходного текста.
https://bitbucket.org/snippets/OlegChulakovStudio/pey7p6
Шаг 3: Разметить
Имея маркеры и кусочки текста, можно легко преобразовать их с учетом любой верстки и смещений.
https://bitbucket.org/snippets/OlegChulakovStudio/9ekL9j
Шаг 4: Склеить
Теперь текст можно собрать обратно, уже с внесенными изменениями.
Телеграм дает много возможностей для создания ботов. Часто их используют для публикации новостей в каналах. Публиковать свои сообщения очень просто: метод
sendMessage принимает текст в трех форматах — text, markdown и html. А вот парсинг и отображение сообщения (например, на сайте) имеют одну большую проблему — получаемый из Телеграма текст не содержит разметки. В нем никак не обозначены ссылки, курсив и т.д.Однако вместе с ним передается список объектов MessageEntity, в которых хранится тип, позиция и длины размеченных частей текста. Мы не нашли библиотек, которые могли бы формировать на основе этих данных, например, markdown-код. При этом любое внесение изменений в исходный текст приводит к несовпадению индексов у последующих MessageEntity. Если начать вставлять теги разметки, то текст начнет смещаться с позиций, указанных в MessageEntity, и будет размечаться не тот контент.
Как мы решили проблему?
Шаг 1: Собрать необходимые данные
Мы собрали все части в один список. В него попали входные и закрывающие индексы.
https://bitbucket.org/snippets/OlegChulakovStudio/Beok58
Шаг 2: Разрезать на части!
По существующим индексам мы порезали сообщение на части, начиная с конца. В результате получили маркированный список отрезков исходного текста.
https://bitbucket.org/snippets/OlegChulakovStudio/pey7p6
Шаг 3: Разметить
Имея маркеры и кусочки текста, можно легко преобразовать их с учетом любой верстки и смещений.
https://bitbucket.org/snippets/OlegChulakovStudio/9ekL9j
Шаг 4: Склеить
Теперь текст можно собрать обратно, уже с внесенными изменениями.
$text = implode('', $parts);Движение вбок
Один из наших подписчиков решил наглядно показать принципы работы современных библиотек для DOM-анимаций. Для этого он написал простую библиотеку и попросил нас ею поделиться:
codepen.io/OlegChulakovStudio/pen/JpYWXX
Так, с ее помощью можно переместить блок по диагонали:
Несмотря на небольшой размер, здесь предусмотрена даже поддержка
Напоминаем, что интересные идеи или вопросы вы можете присылать нам на ask@deep.digital.
Один из наших подписчиков решил наглядно показать принципы работы современных библиотек для DOM-анимаций. Для этого он написал простую библиотеку и попросил нас ею поделиться:
codepen.io/OlegChulakovStudio/pen/JpYWXX
Так, с ее помощью можно переместить блок по диагонали:
animation($block, .3,
{
transform: "translate3d({0}px, {0}px, 0px)"
},
{
transform: "translate3d({50}px, {50}px, 0px)"
}
);
Несмотря на небольшой размер, здесь предусмотрена даже поддержка
vw, % и т.д. Если вам интересна тема анимаций, рекомендуем поизучать код.Напоминаем, что интересные идеи или вопросы вы можете присылать нам на ask@deep.digital.
Вы знаете, с какой скоростью вы ехали?
Что делать, если требуется автоматически отображать пользователю медиаконтент в качестве, подходящем скорости его интернет-соединения? Например, если у вас на сайте собственный видеоплеер и вы хотите показать пользователю ролик в максимально хорошем качестве, но чтобы при этом воспроизведение не прерывалось из-за загрузки.
Сперва, разумеется, вам потребуется сделать несколько версий медиафайла разного веса/качества. Затем нужно определить скорость скачивания и на ее основе отобразить подходящий вариант.
Готовится спецификация Network Information API, которая позволит определить параметры сети, но сейчас ее еще рано использовать в production-среде.
В суровом мире кроссбраузерности порой приходится прибегать к менее изысканным решениям. Для этой задачи наиболее популярным является замер времени скачивания заранее известного объема данных (например, изображения):
https://bitbucket.org/snippets/OlegChulakovStudio/6ey8MR
Чтобы результат был точнее, желательно не производить замер во время загрузки страницы или других медиафайлов.
Что делать, если требуется автоматически отображать пользователю медиаконтент в качестве, подходящем скорости его интернет-соединения? Например, если у вас на сайте собственный видеоплеер и вы хотите показать пользователю ролик в максимально хорошем качестве, но чтобы при этом воспроизведение не прерывалось из-за загрузки.
Сперва, разумеется, вам потребуется сделать несколько версий медиафайла разного веса/качества. Затем нужно определить скорость скачивания и на ее основе отобразить подходящий вариант.
Готовится спецификация Network Information API, которая позволит определить параметры сети, но сейчас ее еще рано использовать в production-среде.
В суровом мире кроссбраузерности порой приходится прибегать к менее изысканным решениям. Для этой задачи наиболее популярным является замер времени скачивания заранее известного объема данных (например, изображения):
https://bitbucket.org/snippets/OlegChulakovStudio/6ey8MR
Чтобы результат был точнее, желательно не производить замер во время загрузки страницы или других медиафайлов.
Есть кто дома?
Нам на ask@deep.digital пришел вопрос: «Как сервисы почтовой рассылки вроде MailChimp собирают статистику о прочтении писем?» Рассказываем.
Перед отправкой в HTML-код письма автоматически добавляется тэг
Разумеется, точность такой статистики снижается из-за блокировки изображений в зависимости от настроек почтовых клиентов у пользователей и политик безопасности используемых ими сервисов.
Получить достаточно корректную статистику о повторном прочтении письма пользователем не получится из-за того, что большинство современных почтовых сервисов кэшируют изображения в своих хранилищах.
Нам на ask@deep.digital пришел вопрос: «Как сервисы почтовой рассылки вроде MailChimp собирают статистику о прочтении писем?» Рассказываем.
Перед отправкой в HTML-код письма автоматически добавляется тэг
img. Он ссылается на маленькое прозрачное GIF- или PNG-изображение. Перед отправкой backend генерирует уникальный URL этого изображения для каждого адресата. Когда пользователь откроет письмо в своем почтовом клиенте, изображение начнет скачиваться с сервера, этот запрос будет зафиксирован и факт открытия письма адресатом запишется в базу данных.Разумеется, точность такой статистики снижается из-за блокировки изображений в зависимости от настроек почтовых клиентов у пользователей и политик безопасности используемых ими сервисов.
Получить достаточно корректную статистику о повторном прочтении письма пользователем не получится из-за того, что большинство современных почтовых сервисов кэшируют изображения в своих хранилищах.
Пропустите! Мне только лайк поставить
При разработке сайтов важно не забывать о том, что у посетителей могут быть заблокированы API встраиваемых сервисов. Например, виджетов VK или Facebook, скриптов Google Analytics. Если не учесть эти блокировки, то от части пользователей будут поступать сообщения о том, что в работе сайта есть ошибки.
Чаще всего причиной являются установленные в браузере AdBlock-плагины, но также проблемы бывают связаны с ограничениями доступа (например, у пользователей из Украины сейчас полностью заблокирован VK).
Что делать?
Тестировщику нужно настроить как минимум один браузер на абсолютно беспощадный режим блокировки: установить AdBlock, Ghostery и другие подобные плагины. Включить в них все преднастроенные ограничения, полностью заблокировать обращения к доменам социальных сетей и популярных сервисов.
Frontend-разработчику нужно внимательно проверять все места, где он использует сторонние API. Необходимо обработать все исключения и не допустить возникновения ошибок, которые прервут выполнение кода.
Например, если вы разместили на сайте кнопку Like, а Facebook JS SDK у пользователя не скачался, то он не должен об этом узнать: верстка не должна поехать, а функционал сайта — сломаться.
При разработке сайтов важно не забывать о том, что у посетителей могут быть заблокированы API встраиваемых сервисов. Например, виджетов VK или Facebook, скриптов Google Analytics. Если не учесть эти блокировки, то от части пользователей будут поступать сообщения о том, что в работе сайта есть ошибки.
Чаще всего причиной являются установленные в браузере AdBlock-плагины, но также проблемы бывают связаны с ограничениями доступа (например, у пользователей из Украины сейчас полностью заблокирован VK).
Что делать?
Тестировщику нужно настроить как минимум один браузер на абсолютно беспощадный режим блокировки: установить AdBlock, Ghostery и другие подобные плагины. Включить в них все преднастроенные ограничения, полностью заблокировать обращения к доменам социальных сетей и популярных сервисов.
Frontend-разработчику нужно внимательно проверять все места, где он использует сторонние API. Необходимо обработать все исключения и не допустить возникновения ошибок, которые прервут выполнение кода.
Например, если вы разместили на сайте кнопку Like, а Facebook JS SDK у пользователя не скачался, то он не должен об этом узнать: верстка не должна поехать, а функционал сайта — сломаться.