Как быстро обслуживать ресурсы с отзывчивым размером в Rails 4, используя CDN, не зная заранее размера размещения?
У меня есть стандартная проблема "адаптивной обработки изображений", но с некоторыми сложными поворотами. Я ожидаю, что мне нужно будет создать собственное решение, описанное ниже, но это через несколько месяцев, так что я подумал, что сейчас принесу это сообществу для помощи с моим подходом и началом работы. Я также думаю, что решение, которое я ищу, будет иметь довольно широкую привлекательность, поэтому оно может быть ценным для сообщества в целом.
Эта проблема:
Мы хотели бы предоставить пользователям изображения, встроенные видео и т. Д. (Все, что требует много времени / полосы пропускания для загрузки и меньше при меньшем разрешении), но изменим загруженные размеры в зависимости от размера, который элемент фактически выделяет на странице., Это базовая "адаптивная обработка изображений", применяемая к нескольким другим типам ресурсов (хотя, поскольку мы предоставляем версии файлов с более низкой пропускной способностью для мобильных устройств, я думаю, что это также относится к "адаптивному дизайну"). Но пока не беспокойтесь о других типах контента, давайте сосредоточимся на изображениях.
Нам нужно определить соответствующую максимальную ширину для каждого конкретного размещения ресурса, для каждой точки останова ширины экрана, не предоставляя эту информацию в качестве конфигурации.
Я создаю платформу, которая будет обслуживать страницы, основанные на HTML-шаблонах от разных сторон. Изображения могут подаваться из любой точки на странице, и страницы могут использовать любую стилевую систему, какую захотят, поэтому мы не знаем, какой размер изображения подходит, просто взглянув на ширину экрана. Нам нужно на самом деле оценить максимальную ширину размещения в каждой поддерживаемой точке перебора размеров. Конечно, это может быть сделано вручную заранее с учетом шаблона дизайна, но давайте предположим, что это слишком много работы для этих третьих сторон.
Например, в Twitter Bootstrap 3 изображение, содержащееся в col-md-8, должно иметь ширину не более 720px, если ширина браузера < 768, но если оно было в col-sm-8, оно должно быть меньше 470px. И если бы мы использовали другую платформу в целом, они бы тоже явно были другими. Мне нужно решение, которое может учитывать все, что CSS делает автоматически, потому что я понятия не имею, что будет делать CSS.
Мы не можем выполнять какую-либо обработку во время запроса изображения. Мы полагаемся на CDN (Cloudfront). Они не собираются внедрять наш пользовательский код на каждом из своих периферийных мест, и я не хочу, чтобы посетитель в Нью-Дели или Берлине должен был отправлять еще один запрос по всему земному шару, для каждого размера активов, прежде чем они узнают, что последний URL Так что это исключает такие решения, как это решение на основе контроллера и сценарий PHP Adaptive-Images.
Нам нужно, чтобы это было быстро. На стороне сервера достаточно места для маневра, поскольку кэширование с Rails 3 и 4 очень просто и гибко, но мы, вероятно, не можем использовать jQuery.width() для каждого элемента по соображениям производительности. В конце концов, единственная причина, по которой мы обслуживаем адаптивные изображения, заключается в уменьшении времени загрузки страницы. Но у нас есть доступ к jQuery в целом, и мы, возможно, могли бы загружать Modernizr все время, если бы нам это было нужно (в настоящее время он включен только для низкого IE с условным HTML).
Мы не доверяем заголовкам User-Agent настолько, чтобы на них основывалась ширина нашего браузера. Мне нравится идея, лежащая в основе mobvious 1, 2 и ее друзей- отзывчивых изображений, но существует так много версий браузеров на ТАМ множестве различных устройств. Насколько сложно было бы построить действительно надежную систему для определения ширины браузера по сравнению с прямым вычислением с использованием JS?
Клиентам без javascript (и, следовательно, сканерам) понадобится доступ к изображению. Кажется, самое простое решение - включить
<noscript>....</noscript>
с канонической, самой большой версией изображения внутри.
Решение Кажется, что единственный способ сделать это состоит в том, чтобы:
- Пусть сервер пропустит все доступные размеры, а затем вычислит ширину каждого элемента на стороне клиента с помощью jQuery каким-либо эффективным способом (возможно, с использованием $.css_width() или какого-то специального сценария). Таким образом, сервер будет создавать:
<span data-respv-img-id="picture_of_unicorns"></span>
<noscript data-respv-img-id="picture_of_unicorns" data-img-720- url="//cdn.example.com/assets/picture_of_unicorns_720x480" data-img-320-url="//cdn.example.com/assets/picture_of_unicorns_320x260" data-img-120-url="//cdn.example.com/assets/picture_of_unicorns_120x80">
<img src="//cdn.example.com/assets/picture_of_unicorns_720x480" alt="Magical unicorns">
</noscript>
И если мы на маленьком экране и только 120 подходит, JS превратит это в:
<span data-respv-img-id="picture_of_unicorns">
<img src="//cdn.example.com/assets/picture_of_unicorns_120x80" alt="Magical unicorns">
</span>
- ИЛИ пусть сервер выполняет какую-то предварительную обработку, поэтому он точно знает, какой размер изображения подходит для каждого размещения на каждой ширине браузера, и обеспечивает:
<span data-respv-img-id="picture_of_unicorns"></span>
<noscript data-respv-img-id="picture_of_unicorns" data-img-1200- url="//cdn.example.com/assets/picture_of_unicorns_720x480" data-img-1024-url="//cdn.example.com/assets/picture_of_unicorns_320x260" data-img-768-url="//cdn.example.com/assets/picture_of_unicorns_120x80">
<img src="//cdn.example.com/assets/picture_of_unicorns_720x480" alt="Magical unicorns">
</noscript>
И мы получаем то же самое, что и другой подход. Но на этот раз работа jQuery была намного проще, поскольку мы перенесли всю работу по определению размера на сервер. Но это требует загрузки полного стека браузера на стороне сервера для генерации каждого запроса. Это нормально с кэшированием, но, безусловно, приносит много сложностей.
Обратите внимание, что оба эти решения позволят загружать изображения на основе прокрутки, что является еще одним аспектом, который мне нужно реализовать, но не то, что нам нужно обсуждать сейчас.
Короче говоря: какой подход вы бы порекомендовали? Можете ли вы придумать лучший способ?