css

Как рождался CSS

Мне стало интересно: автор «Виолы» первым догадался отделить стилизацию элементов от структуры, или эта идея уже активно обсуждалась? Нашёл объёмное исследование о том, как зарождался CSS. Браузер «Виола» со своими собственными таблицами стилей там тоже упомянут.

Оказалось, что таблицы стилей как концепция гораздо старше самого веба. Ещё в конце 1970-х Брайан Рид из Университета Карнеги—Меллон разработал систему разметки «Скрайб». Она стала темой его докторской диссертации, защищённой в 1980 году, за которую в 1982-м Рид получил премию имени Грейс Мюррей Хоппер, присуждаемую Ассоциацией вычислительной техники (ACM).

Язык разметки описывал структуру документа — слова, строки, страницы, интервалы, заголовки, подстрочные примечания, нумерацию, оглавление и т. д. — по принципу, близкому к HTML. Далее специальный компилятор использовал базу стилей (Style Database), где хранились определения оформления — шрифты, поля, отступы и прочие параметры.

Сравнение разметки: ручные пометки, слова-разделители, escape-символы (@i, @b, @begin) для курсива, жирного, цитат.
Описание разметки «Скрайба», скриншот из руководства (октябрь 1980 года)

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

Синтаксис «Виолы» был не самым продуманным, не был и единственным, но был одним из первых — он появился уже в 1993 году.

Оставить комментарий

STG: таблицы стилей в «Виоле»

Чем меня в своё время поразила «Виола» в самое сердечко, — предвосхищением идеи стилевых таблиц и браузерного языка программирования. Мне очень нравятся такие пророческие находки, хочется увидеть как они были сделаны и как автор до этого вообще дошёл.

«Википедия» в своё время заронила интерес, но полностью тему не раскрыла — про стилевые таблицы этого браузера там написано совсем мало, да ещё и с ошибками, как я смог убедиться. «Спецификация», если так можно назвать страницу, сохранившуюся благодаря стараниям «Веб-архива», тоже показалась неполной…

Оказалось — показалось, в браузере было реализовано даже меньше.

Несмотря на простоту спецификации, «Виола» мало что из описанного умела, пришлось дописать. Сейчас всё, надеюсь, работает так, как задумывал автор. Интересный момент — код на Си только парсит стили, остальным занимается интерпретируемый код, написанный на языке программирования, реализованный в браузере.

Стилевые таблицы подключаются тегом LINK и имеют расширение .stg, хотя это не обязательно, но в спецификации так:

<link rel="style" href="HTML_sodium.stg">

Таблиц может быть подключено много и они работают «вниз», то есть от момента включения в код ниже места включения применяются стили, которые там описаны.

Селекторов всего два — можно выбрать тег или стиль тега (это работает немного не так как в CSS):

(BODY,SECTION
     BGColor=green
     FGColor=red
     (P)
     (KBD
          BDColor=black
          border=1
     )
)

Что тут написано? Что в тегах BODY и SECTION будет зелёный фон и красный цвет шрифта, а кроме того эти атрибуты унаследуют теги P и KBD, причём у последнего будет ещё и чёрный бордюр.

Атрибутов, к слову немного, в основном это характеристики шрифтов, цвет, бордюр и кое-какие мелочи, вроде организации мигания текста или выравнивания.

Ещё есть стилизованный браузером элементы, некие встроенные стили (например, WARNING, NOTE и так далее), которые можно навешивать на произвольные теги при помощи атрибута STYLE. На картинке пример того как выглядит встроенный стиль WARNING: оранжевый бордюр и картинка.

Скриншот редактора кода с HTML-файлом html_5.html, содержащим заголовок STYLE и параграф с классом WARNING, отображающий предупреждение с иконкой восклицательного знака.

К тегам, помеченным атрибутом STYLE тоже можно применять собственные стили:

(P
    BGColor=white
    FGColor=black
    {STYLE "WARNING"
        FGColor=red
        fontSlant=italic
    }
)

У тега P здесь белый фон и чёрный цвет шрифта, а если у него есть атрибут STYLE, равный WARNING, то добавляются ещё два стиля, определяющие красный шрифт наклонного начертания.

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

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

Скриншот ViolaWWW с заголовком «A simple stylesheets test»: красный фон H1, синие и зелёные блоки адресов, текст с разными стилями.
Тестовый пример с сайта «Виолы», открытый собранным мною браузером

4 комментария

Заказ щедро оплачен

На днях баловался со стилями магазина «Озон» при помощи браузерного плагина Stylus — избавлялся от навязчивой рекламы внутри списка товаров. Это те бесячие предложения, которые игнорируют выбранную сортировку.

Скрипт приводить не буду, всё равно его приходится править время от времени — у «Озона» используется фреймворк «vue» и из-за этого всё время меняются имена классов.

Заказ №123456789-1234 от 3 февраля: оплачен 534 ₽ Озон Картой, доставка в пункт Ozon в Казани, получатель Евгений Степанищев, бесплатно.

Заодно, в качестве баловства, заменил себе надпись «Заказ оплачен» на «Заказ щедро оплачен». Эту часть могу привести, может кто-нибудь себе захочет так же сделать:

.tsBodyM[data-widget="orderStatus"]::before {
    content: 'Заказ щедро оплачен';
    color: var(--ozTextPrimaryNegative);
    font-size: var(--bodyMFont);
    line-height: 1.29;
}

2 комментария

«Магический шар» ★

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

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

Из того набора атрибутов и тегов, что тогда были доступны, мне довелось использовать всё, кроме одного-единственного атрибута ISMAP у картинки, ну просто не возникло ситуации, в которой он мог мне бы пригодиться.

Использование его в те годы могло бы выглядеть как-то так:

<A HREF=/cgi-bin/action.pl><IMG SRC=/i/pict.gif WIDTH=200 HEIGHT=100 ISMAP></A>

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

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

На тёмном фоне фиолетовый круг с надписью «My sources say no» (Мои источники говорят «нет»).
«Магический шар» из прекрасного фильма «Трасса 60»; с отрисовкой деталей я не стал заморачиваться

Я уже несколько лет как не верстаю, но почему-то этот атрибут ISMAP мне всё никак не давал покоя. Как будто брошенная на последней странице книга — всё тянуло найти ему какое-то применение.

И вот два года назад меня осенило использовать его в вёрстке «магического шара» из фильма «Трасса 60». Если не смотрели, там у главного героя был шар, который давал ответы на заданные вопросы, если его потрясти.

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

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

HTML с таким подходом становится довольно жирным — у меня получился 1,2 мегабайта, но по нынешним временам это не объём.

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

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

11 комментариев

text-decoration-line

Wavy (30.66КиБ)

Есть такая договорённость в вебе — псевдоссылки (которые похожи на ссылки, но не уводят со страницы) подчёркивать не сплошной чертой, а прерывистой или точечной. Обычно такую черту делают бордюром снизу тега, но если настоящие ссылки сделаны через text-decoration: underline, то черта оказывается на разной высоте: у ссылок она выше, чем у псевдоссылок.

Сейчас браузеры начинают поддерживать свойство text-decoration-line, но с переменным успехом — Хром — поддержка выключена по-умолчанию, Файерфокс поддерживает в полном объёме, Сафари как утверждает «КенАйЮз» — не поддерживает, ИЕ — тоже.

Оказалось, в данном случае — доверяй, но проверяй. «Сафари» (по крайней мере восьмая версия) всё-таки частично поддерживает это свойство, просто не все значения — отрисовываются wavy (на скриншоте), double и solid (остальные значения превращаются в solid).

4 комментария

Короткий способ определить есть ли поддержка dataURI

Придумал короткий способ определить поддержку data URI в браузере:

<script src="data:text/javascript,self.dataURI=1"></script>

Потом просто проверяете у window свойство dataURI, если оно есть, то есть и поддержка. Способ не работает в IE8 и IE9 — тот и другой не умеют загружать Джаваскрипт этим образом. Собственно, меня это не волнует — мне как раз и нужно определить, что Джаваскрипт так работает, но если вам нужно не это, то должен работать вот такой способ:

<link rel="stylesheet" href="data:text/css,html{font-size:99px}">

То есть устанавливаем у тега HTML какое-нибудь свойство, которое потом в BODY перекроем, а позже, чтобы убедиться, что поддержка дата-ури есть, смоторим что вышло (тут я при помощи jQuery это делаю):

/99/.test($('html').css('font')); // true, если есть поддержка dataURI

Оставить комментарий

Use SVG

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

Одним из главных помощников в такой вёрстке является, без сомнения, формаг СВГ — формат векторной графики, который на данный момент поддерживают все распространённые браузеры (включая ИЕ, с девятой версии). Особенно приятно, что его можно включать прямо внутрь ХТМЛя, это очень удобно — если СВГ используется для кучи мелких значков на странице, то не будет лишних соединений с сервером — ведь всё грузится вместе с основным кодом.

Но встаёт другая проблема — проблема повторного использования. Если одни и те же значки присутствуют на странице в изобилии, страница будет распухать, что печально.

К счастью, есть выход. СВГ — гибкая штука, в этом формате есть возможность использования частей изображения повторно. Первым шагом нужно определить тег-контейнер с необходимыми нам изображениями, по одному в теге symbol. У каждого из них будет собственный идентификатор, по которому мы ниже будем на них ссылаться:

<svg style="display:none">
    <symbol id="folder" viewBox="0 0 49.833 67.167">
        <!-- код не рабочий, только для примера -->
        <path d="M15.938,67.…"/>
        <path d="M3.59,30.531c…"/>
    </symbol>
    <symbol id="file" viewBox="0 0 49.833 67.167">
        <path d="M12.233c0.…"/>
        <path d="M3.28C2.76…"/>
    </symbol>
</svg>

Тут у нас два изображения — folder и file, на которые мы можем сослаться следующим образом:

<svg width="28" height="37">
    <use xlink:href="#folder"/>
</svg>

<svg width="28" height="37">
    <use xlink:href="#file"/>
</svg>

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

svg.green {
    fill: green;
}

svg.red {
    fill: red;
}

Классы можно повесить на ссылающиеся теги СВГ, жаль только этот способ полон ограничений. Кроме как в ФФ более избирательные селекторы использовать не удаётся — всё, что ниже тега use для таблицы стилей как будто не существует. Если и есть какой-то способ это починить, я его не нашёл.

5 комментариев

Chrome (but not Safari) CSS hack

Обратил внимание, что половина интернета сбилась с ног в попытках найти стильевой хак для «Хрома», который не срабатывал бы в «Сафари». Неясно почему его ещё никто не придумал, у меня на это ушла пара минут:

@supports (top: 0__qem) {
    .chrome-only {
        border: 1px solid #000; /* стиль только для Chrome (не Safari) */
    }
}

Работает начиная с 28-го «Хрома» и не работает на «Сафари» (включая последнюю версию 7.0.5). Принцип простой, как чихание — «Сафари», даже самый свежий, не поддерживает конструкцию «@supports», правда её поддерживает Файерфокс и зомби «Оперы».

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

Чтобы отсечь лишнее, я использую нестандартную единицу измерения Вебкита — «__qem», я о ней писал несколько лет назад. Вместе получается, что стиль в «Сафари» не срабатывает, потому что тот не поддерживает «@supports», а в остальных браузерах — потому что они не поддерживают «__qem».

Естественно, обёртки над Вебкитом (новая «Опера», браузер «Яндекса» и прочее) стиль увидят — но на то они и обёртки.

3 комментария

CSS variables

Константы в ЦСС (которые почему-то называются «переменными») — прекрасная штука, особенно в сочетании с вычисляемыми выражениями (calc). Я рад, что браузеры постепенно внедряют эксперементальную поддержку, с нынешними темпами обновшения есть надежда начать это использовать уже очень скоро (calc я уже использую, его ограниченно поддерживает даже IE9).

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

В 31-м Файерфоксе (он пока ещё в бете) синтаксис констант сменился и теперь будет включен по-умолчанию. Выглядит это так:

:root {
  --bgcolor: #000; 
}

body {
  background-color: var(--bgcolor);
}

Как видите, префикс «var» сменился на два минуса в полном соответствии с изменениями в стандарте. Чем не устроил предыдущий синтаксис мне не интересно, но этот префикс набирать определённо быстрее — всего-то надо нажать одну клавишу два раза.

4 комментария

IE9 и таблицы

IE9 и таблица (18.31КиБ)

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

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

Дело оказалось в пробелах между ячейками — верстальщик отформатировал шаблон, чтобы он лучше читался, и все браузеры всё показали правильно, один девятый Эксплорер сошёл с ума. Лечится проблема запросто — либо убираем форматирование в шаблоне, либо убираем его прямо в браузере.

Я выбрал второй путь. Пусть лучше шаблон выглядит читаемо, а костыль для девятого Эксплорера всегда можно будет убрать лёгким движением руки. Выглядит он вот так, кстати (используется jQuery, само собой):

$("table tr").contents().filter(function() {
    return this.nodeType == 3;
}).remove();

16 комментариев

Свёртка в вебе

Я как-то пропустил момент, когда фильтры SVG стало можно накладывать на обычный тег IMG, а не на изображения внутри SVG же. Любопытные эффекты можно делать, например, можно наложить свёртку для выделения краёв и это будет работать:

<style>
    .edge {
        -webkit-filter: url(#edge);
        filter: url(#edge);
    }
</style>

<svg style="width: 0; height: 0">
<filter id="edge">
<feConvolveMatrix kernelMatrix="-1 -1 -1 -1  9  -1 -1  -1  -1" />
</filter>
</svg>

<image src="sample.jpg" class="edge">

Магические числа в матрице — специальное ядро.

Впрочем, и раньше можно было внедрить в ХТМЛ СВГ-картинку и наложить сверху фильтр, ничего особенного, но мороки чуть больше. При желании этот фильтр можно унести прямо в ЦСС при помощи data URI, но тогда он продублируется два раза — для префиксной и безпрефиксной формы (несмотря на уверения «Кэнайюз», «Хром» и «Сафари» отказались работать без префикса).

С таким возможностями, немудрено, что онлайновых «фотошопов» развелось, как грязи. Немного помучавшись с консолью, можно найти способ как поменять матрицу и это тоже будет работать! Например, вот так меняется число по центру (где у меня в примере девятка записана):

var arr = document.getElementById('edge').childNodes;

for (var i = 0; i < arr.length; i++) {
    if (arr[i].kernelMatrix) {
        arr[i].kernelMatrix.baseVal.getItem(4).value = newvalue;
        break;
    }
}

Осталось только соединить этот код с «крутилкой» и готов онлайн-фильтр «выделение краёв».

10 комментариев

CSS parent selector

Тема родительского селектора в ЦСС всплывает ужа давно, если не ошибаюсь, в Вебките даже как-то был эксперементальный синтаксис для его поддержки.

Что такое родительский селектор? О, это очень простая и мощная штука, к примеру, если клиент выбрал что-то в каком-то окне, нужно всё окно спрятать. При помощи ЦСС это можно было бы сделать так:

.window < :checked { /* экспериментальный синтаксис родительского селектора из Вебкита */
    display: none;
}

Сразу скажу, задумка мощная, а реализация плохая. Какую проблему тут видно сразу? Непонятно что значает этот знак. Непосредственного родителя мы здесь выбираем или любого? Если непосредственного, как выбрать любого и наоборот?

Все синтаксисы родительского селектора (включая, например, :parent) грешат чем-то подобным — они не гибкие или неоднозначные.

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

.window > (:checked ~ :checked) {
    display: none;
}

Всё сразу становится логично, на мой взгляд: применить стиль к тегу с классом window, у которого два непосредственных потомка-соседа находятся в состоянии «checked».

23 комментария

IE 10 CSS hack

Придумал CSS-хак для Эксплорера 10-й версии, срабатывающий только в режиме совместимости, похоже, что все существующие хаки в нём не работают.

@media , {
    .:valid, body {
        background: red; /* будет красным в Internet Explorer 10 (режим совместимости) */
    }
}

Проверил при помощи сайта «Браузер шотс» ложные срабатывания, как будто всё в порядке, их нет. Не проверял на IE11, не знаю будет ли там работать. Если у кого-то под рукой есть, напишите в комментариях, пожалуйста, интересно же. Ну и под другими браузерами всё равно будет нелишним проверить, напишите срабатывает или нет.

Так же придумал новый хак для обычного режима IE 10:

@media all\0 {
    _:valid, body {
        background: red; /* будет красным в IE 10 */
    }
}

И ещё один:

_:valid\0, body {
    background: green; /* будет зелёным в IE10 */
}

Так же не тестировал на IE11 (мне негде).

33 комментария

-khtml-border-radius

На «Хабре» постоянно всплывает тема того, что, якобы, никогда не существовало свойства «-khtml-border-radius». Непонятно чем руководствуются люди, разносящие этот слух. Можно сказать, что это свойство неактуально — всё-таки, Konqueror, который поддерживает этот префикс, — вымирающий вид, но свойство-то существовало!

Konqueror -khtml-border-radius (11.56КиБ)

Вот на скриншоте вверху версия 4.4 отображает свойство -khtml-border-radius, которое появилось в версии 4.2. Правда указывать префикс имело смысл совсем недолго — та же 4.4 уже поддерживает то же свойство и в беспрефиксной форме.

Оставить комментарий

Размытие шрифта на Ретине в Сафари

Шрифт на Ретине (16.68КиБ)

Как и ожидалось, Ретина ещё какое-то время будет порождать баги. Наткнулся на необычное поведение «Сафари» (в свежем «Хроме» баг не повторился) — один из шрифтов смотрелся размытым (на скриншоте слева). Оказалось во всём виноват фильтр -webkit-filter: opacity, наложенный для анимированного появления окна.

Заменили на обычное свойство opacity, стало выглядеть, как на скриншоте справа.

2 комментария

Оптимизация картинок поворотом

Есть такой старый трюк, который с развитием CSS получил новое прочтение. Дело в том, что при упаковке изображения в графические форматы, в основном, сканируют и упаковывают изображение, двигаясь по его линиям слева направо. Первом об этом на русском языке написал, думаю, Лебедев, вот что написано в книге «Реактивные вебсайты», соавтором которой я являюсь:

Изображения GIF хорошо поддаются оптимизации. В параграфе №8 «Ководства» Артемия Лебедева есть небольшое, но интересное исследование особенностей этого формата. Вывод из параграфа простой: чем больше на картинке горизонтальных линий одного цвета, тем лучше сжимается изображение. Алгоритм компрессии LZW, применяемый в GIF, вообще лучше сжимает регулярные горизонтальные структуры в пределах одной линии.

Соответственно, если есть возможность повернуть картинку, то, бывает, она сжимается лучше. Где-то была хорошая статья с колесом на эту тему, не могу найти. Смысл там в том, что изображение с колесом можно поверкнуть как угодно, разницы нет, у колеса, поставленного на попа, нет «верха» и «низа», а вращение даёт возможность упаковать картинку эффективнее.

Но не всегда так везёт, гораздо чаще, согласитесь, встречаются изображения, которые повернуть нельзя. Значит о способе забываем?

Вот тут нам и пригодятся нововведения в ЦСС. Берём свою картинку, сохраняем ещё три копии повёрнутые на 90°, 180° и 270°, а потом все четыре изображения оптимизируем, выбираем то, которое меньше занимает. А дальше просто поворачиваем его при помощи ЦСС (я ещё фильтр для старых ИЕ добавил и некоторые свойства для других браузеров):

.rotate90 {
    filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); /* IE 5.5+ */
    -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; /* IE 8 */
    -ms-transform: rotate(90deg); /* IE 9 */
    -o-transform: rotate(90deg); /* Opera 10.5+ */
    -webkit-transform: rotate(90deg); /* Chrome, Opera 15+, Safari 3.1+, Android 2.1+, iOS 3.2+ */
    -moz-transform: rotate(90deg); /* FF 3.5+ */
    transform: rotate(90deg); /* FF 16+, IE 10+, Opera 12.1-14.99 */
}

Картинка поворачивается браузером и визуально остаётся как была.

Вообще, конечно, можно поворачивать на любой угол, если фон картинки прозрачный или совпадает с окружающим фоном, но в старых ИЕ для этого придётся использовать другой фильтр — Matrix, формула расчёта параметров такая:

progid:DXImageTransform.Microsoft.Matrix(
  M11 = cos(угол),
  M12 = -sin(угол),
  M21 = sin(угол),
  M22 = cos(угол),
  sizingMethod = 'auto expand'
);

Метод не лишён недостатков, конечно. Во-первых, всё это может сказаться на производительности, особенно в старых Эксплорерах (в последнем даже сомнений нет — скажется). Во-вторых, как видно из версий, которые я добавил в ЦСС, не все версии браузеров поддерживают поворот, правда их доля совсем невелика и продолжит снижаться.

15 комментариев

Как узнать, что пользователь печатает веб-страницу на принтере?

У нас тут задача в процессе производства продукта появилась — занести в лог, что пользователь сделал попытку печати чего-либо в браузере. Есть событие onbeforeprint, но оно есть только в Эксплорере и Файерфоксе.

Придумал такое решение — перед печатью браузер накладывает стиль CSS для печати, если он есть, этим можно воспользоваться:

@media print {
    body {
        background: url(http://example.org/user-tries-to-print.php);
    }
}

Браузер попытается загрузить фоновое изображение (и загружает, я попробовал), выполнится серверный скрипт и положит в логи то, что нужно.

15 комментариев

Обнаружение Ретины

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

Наиболее животрепещущий вопрос — подготовка изображений для Ретины.

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

В вебе бо́льшая часть графики выглядит не очень (хотя масса сайтов уже подготовилась). Для того, чтобы стало хорошо, все изображения надо готовить вдвое большего размера, при этом указывая для них в коде вдвое меньший размер, тогда проявляется вся мощь Ретины — будет видно самые мелкие детали изображения и пропадёт размытие.

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

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

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

Вообще, у Джипега, например, есть прогрессивная загрузка — по мере загрузки «прогрессивное» изображение не грузится сверху вниз, а становится всё чётче и чётче (хорошая иллюстрация этого есть в одном из параграфов «Ководства»). Надо будет поэксперементировать в эту сторону — нельзя ли прервать передачу на нужной детализации, если экран не «ретиновый».

А пока, у меня такое решение. Используем старые-добрые «печеньки» и mod_rewrite.

На стороне клиента первой строкой каждой нашей страницы ставим проверку по «ретиновые» экраны с установкой «печенья»:

<script>if(window.devicePixelRatio>=2)document.cookie='retina=1'</script>

Этот скрипт выполнится первым и все дальнейшие запросы на сервер будут содержать строку «retina=1», если мы имеем дело с Ретиной. Все изображения, для которых у нас есть две копии — обычная и «ретиновая» (в два раза большая) называем одинаково, но с постфиксом «@2x» для большей, при этом в коде указываем данные разрешения для более мелкой картинки:

<img src="/images/owl@2x.jpg" width="400" height="560" alt="Совушка">

Сейчас, конечно, Апач теряет популярность, но я воспользуюсь синтаксисом mod_rewrite, желающие могут переделать в Энжин Икс или какой-то другой синтакис:

RewriteEngine On

RewriteCond %{HTTP_COOKIE} !retina=1
RewriteRule (.*)@2x\.(gif|jpe?g|png|webp) $1.$2 [L,NC]

Этот код означает, что если не установлено «печенье» «retina=1», то нужно убрать постфикс «@2x» из имени картинки.

В итоге, если у нас Ретина, «печенька» ставится в самом начале, все дальнейшие запросы к серверу идут с ней и картинки грузятся как указано в коде — например, если указано «owl@2x.jpg», то эта картинка и грузится.

Если у нас обычный экран, «печеньки» нет, запросы к серверу идут без неё и из картинок вырезается постфикс «@2x», т. е. картинка «cat.jpg» грузится по своему имени, а вместо «owl@2x.jpg» загрузится «owl.jpg».

Voilà!

66 комментариев

Инвертирование в CSS без фильтров

Немногие знают, что инвертирование части ХТМЛ-страницы можно и без новомодных ЦСС-фильтров. Правда, количество браузеров, где это можно сделать, всё уменьшается. В данный момент такая возможность всё ещё остаётся в Эксплорере (версия 8 и выше) и «Опере» (7.0 и выше). Так как «Опера» скоро перейдёт на Вебкит, где этой возможности нет и не было, останется один Эксплорер. Файэрфокс лишился поддержки этой функции в версии 3.0 и возвращать её пока не планирует.

Я говорю о поддержке значения invert свойства outline-color. Это значение говорит браузеру, что нужно инвертировать всё, что лежит ниже. Пользоваться не очень-то удобно, но сойдёт при необходимости, результат может выглядеть, например, так:

Инвертирование при помощи outline-color (33.90КиБ)

Наложить сверху элемент с аутлайном можно любым способом, я использовал position: absolute:

<style>
.invert {
    outline: invert solid 75px;
    position: absolute;

    width: 50px; height: 0;
    margin: 75px 0 0 75px;
}
.content {
    width: 200px;
    height: 150px;
    position: absolute;
    left: 200px;
    top: 200px;
    text-align: center;
}
</style>

<div class="content">
    <div class="invert"></div>
    <img src="/i/foto.jpg">
</div>

Для того, чтобы высчитать размеры накрывающего блока, нужно немного арифметики. У меня большую размерность имеет ширина (накрываемый блок размером 200×150), поэтому будем плясать от неё. Высота накрывающего блока должна быть в этом случае равна нулю, ширина — разности между шириной и высотой накрываемого блока, outline-width, margin-top и margin-left — половине высоты накрываемого блока.

Думаю, ни для кого не составит труда самостоятельно провести вычисления для обратного случая — когда высота больше ширины.

1 комментарий

Тонкое подчёркивание ссылок с разрывами на буквах «р», «у» и других

У меня на сайте два изменения. Во-первых, я опять втихую увеличил шрифт (я этим занимаюсь время от времени), во-вторых, я изменил стиль подчёркивания ссылок. После сайтов Тёмы и Ильи Бирмана, подчёркивание у меня казалось тяжёлым и давящим, а у них — естественным и воздушным.

Но просто сделать так же не интересно, и я решил сделать лучше. Спорно получилось ли лучше, тут есть простор для экспериментов.

Подчёркивание ссылок и Тёмы и Ильи сделано одинаково — убрано родное подчёркивание, а взамен установлено свойство border-bottom, задающее бордюр толщиной в один пиксель. Мне в этом подходе не понравилось, что бордюр находится неестественно далеко — за хвостиками букв «у», «р» и прочих.

Сначала позвольте показать что получилось, обратите внимание на разрыв на хвостике «р», когда я добился более плотного прилегания, оказалось, что перечёркивание хвостов меня не устраивает, хорошо что удалось это поправить:

Результат (21.88КиБ)

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

Я довольно долго эксперементировал и нашёл, в конце-концов, решение — я сделал цветной однопиксельный задний фон (простой ГИФ в data URI) по одному для каждого цвета ссылок: непосещённые, посещённые и с наведением мыши, а потом просто спозиционировал так как мне понравилось.

И вот тут меня ждала неприятность. Дело в том, что некоторое время назад появился способ, позволяющий узнать какие сайты вы посещали; интернет пестрел скриптами, которые в шутку журили вас, если обнаруживали, что вы до этого посещали какие-то порносайты.

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

Естественно, браузеры не могли не отреагировать на эту дыру. Кажется, Файерфокс первым отреагировавшим на проблему — они предложили «врать» разработчику о стиле посещённых ссылок и разрешили менять для них только строго определённый список ЦСС-правил.

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

В голове перед сном я прокручивал список разрешённых к изменению свойств и одно из них, background-color показалось мне подходящим, чтобы решить мою проблему. Я нарисовал ГИФ единичной ширины, совершенно белый, но с одним прозрачным третьим с конца пикселем:

Мой фон (15.23КиБ)

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

Ок, это сработало для посещённых ссылок, но в «Хроме» и «Сафари» меня ждал неприятный сюрприз: на мгновение, до того как браузер успевал отрисовать мой ГИФ на заднем фоне, все ссылки выглядели уродливо: был виден их цветной задний фон:

Грусть-печаль (36.94КиБ)

Я подумал, что мне бы помогло, если я бы как-то рисовал подходящий фон без картинки. Долго думать не пришлось, я когда-то эксперементировал с картинками, сделанными при помощи linear-gradient, поэтому для меня было естественными решением сделать стиль, который рисует нужный мне фон этим способом.

Получился следующий стиль:

a {
    background: #00e url(data:image/gif;base64,R0lGODlhAQA7APABAP …и так далее… AAACCISPqcvtEEwBADs=) 0 100% repeat-x;
    background-image: -webkit-linear-gradient(90deg, #fff 0, #fff 2px, rgba(0,0,0,0) 2px, #fff 3px, #fff 59px);
}

Это полностью решило проблему — мигание на вебкитовских браузерах пропало. Кстати, я применил стиль линейного градиента, в новом формате — он работает в «Сафари» с версии 5.1 и в «Хроме» с десятой. Мне кажется, в этом нет ничего страшного — доля старых браузеров, в данном случае, ничтожна мала.

Когда я поставил подчёркивание куда мне хочется, возникла другая проблема. Эстетическая. Подчёркивание довольно уродливо перечёркивало нижние выносные элементы букв. На память, по аналогии, пришло моё баловство с фильтром Glow в Интернет Эксплорере. Там удавалось добиться интересных эффектов с задним фоном, поскольку эффект ложится и на него. Тут у меня ситуация такая же, но фильтров больше не существует, правда есть их реинкарнация —W3C заботливо слизало идею в другом синтаксисе.

После некоторых экспериментов, я решил, что тут подходит text-shadow — если сделать тень белого цвета, она очень хорошо закрашивает задний фон. Для этого я сделал несколько однопиксельных теней, и одну двухпиксельную на самой границе разрыва — тогда края разрыва размываются и он становится более мягким. И поднял тень немного вверх, иначе некоторые буквы давали неприятные «блики» на подчёркивание:

a {
    text-shadow: 1px -1px 1px white, -1px -1px 1px white, 2px -1px 2px white, -2px -1px 2px white;
}

В браузерах, которые этот стиль не поддерживают, подчёркивание просто не будет разорвано.

Стиль, в результате выглядит примерно так:

a {
    text-shadow: 1px -1px 1px white, -1px -1px 1px white, 2px -1px 2px white, -2px -1px 2px white;
    text-decoration: none;

    background: #00e url(data:image/gif;base64,R0lGODlhAQA7APABAP … и так далее … AAACCISPqcvtEEwBADs=) 0 100% repeat-x;
    background-image: -webkit-linear-gradient(90deg, #fff 0, #fff 2px, rgba(0,0,0,0) 2px, #fff 3px, #fff 59px);
}

a:visited {
    color: #551a8b;
    background-color: #551a8b;
}

a:hover {
    background-color: red;
    color: red;
}

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

59 комментариев

← 1 2 3 4 5 6 →