Показаны сообщения с ярлыком CSS. Показать все сообщения
Показаны сообщения с ярлыком CSS. Показать все сообщения

06.08.2009

Однопиксельные прозрачные уголки

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

Есть более крутой способ, суть его в следующем:

Упрощенный код для понимания идеи:

.corners {
    background-color: #80aaff;
    margin: 0 1px;
    padding: 1px 0;
}

.corners-i {
    background-color: #80aaff;
    margin: 0 -1px;
}

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

Достоинства способа:

  • Всего лишь один доп. элемент.
  • Уголки получаются прозрачные, а значит не нужно их «красить» в цвет фона.
  • Нет JS, экспрешенов, спрайтов.

Недостатком, конечно, является ограничение радиуса скругления в 1 пиксель :)

Рассмотренный способ отлично сочетается с бордер-радиусом, то есть, в браузерах поддерживающих border-radius используем border-radius, в остальных браузерах задействуем доп. элемент .corners-i и делаем однопиксельные уголки.

24.06.2009

border-radius спешит на помощь

В соавторстве с Вадимом Макишвили

Для реализации скругленных уголков мы искали максимально легкое решение — отсутствие дополнительной разметки, минимум CSS и JS. Конечно, есть очень мощные средства, например, rocon, но нам они показались избыточными и громоздкими.

Идея была в том, чтобы использовать CSS-свойство border-radius, которое поддерживают некоторые прогрессивные браузеры:

  • Firefox начиная с версии 1.0 (~24% пользователей)
  • Safari начиная с 3.0 + Chrome (~2%)
  • Konquerer (~0,05%)

Итого, для ~25% пользователей уголки можно рисовать средствами браузера — уже неплохо.

Смешно, но свойство border-radius, которое есть в CSS3, пока не поддерживается ни одним браузером. Однако, некоторые браузеры поддерживают аналогичные проприетарные свойства, например, -moz-border-radius в Firefox.

.corners {
    /* Возможно какой-нибудь браузер в будущем, будем надеяться IE */
    border-radius: 4px;
    /* WebKit (Safari/Chrome) */
    -webkit-border-radius: 4px;
    /* KHTML (Konquerer) */
    -khtml-border-radius: 4px;
    /* Возможно Opera в будущем */
    -opera-border-radius: 4px;
    /* Gecko (Firefox) */
    -moz-border-radius: 4px;
}

Для остальных браузеров, не поддерживающих border-radius, будем яваскриптом вставлять доп. элементы для реализации уголков.


// Проверяет, поддерживает ли элемент elem CSS-свойство border-radius.
var isBorderRadiusSupported = function (elem) {
    var s = elem.style;
    return typeof s.borderRadius === "string" ||
           typeof s.WebkitBorderRadius === "string" ||
           typeof s.KhtmlBorderRadius === "string" ||
           typeof s.OperaBorderRadius === "string" ||
           typeof s.MozBorderRadius === "string";
};

// Добавляет внутрь элемента elem доп. элементы реализующие уголки.
var wrapInCorners = function (elem) {
    // Реализуем уголки любым известным способом
    $(elem).prepend('<i class="lt"/><i class="rt"/><i class="lb"/><i class="rb"/>');
};

// Реализует закругленные уголки с помощью доп. элементов
// для браузеров не поддерживающих CSS-свойство border-radius.
var checkCorners = function () {
    // Ищем все элементы с классом corners
    $('.corners').each(function () {
        // Если для данного элемента браузер не поддерживает border-radius
        if (!isBorderRadiusSupported(this)) {
            // Добавляем внутрь элемента доп. элементы реализующие уголки
            wrapInCorners(this);
        }
    });
};

// DOM загрузился и готов к обходу и манипуляциям
$(function () {
    checkCorners();
});

Плюсы решения:

  • HTML льется чистый, без доп. элементов, и, соответственно, лишняя разметка не мозолит глаз ни в статической верстке, ни в XSL-шаблонах.
  • В прогрессивных браузерах (примерно у четверти пользователей) уголки рисуются средствами браузера (максимально быстро).
  • Есть задел на будущее — если IE или Opera надумают реализовать border-radius, то наше решение готово к этому радостному событию.

UPD: В комментариях указали на слабые стороны этого решения. Также откликнулись мои коллеги и помогли улучшить решение по производительности. Спасибо всем! Для этого мне и нужен блог — поделиться решением, собрать фидбек и найти более удачный вариант.

1. Не нужно проверять поддержку border-radius для каждого элемента. Сделаем эту проверку один раз в теге <head> до загрузки контента и добавим соответствующий класс у элемента <html>.

// Проверяет, поддерживает ли браузер CSS-свойство border-radius.
var isBorderRadiusSupported = function () {
    var s = document.documentElement.style;
    return typeof s.borderRadius === "string" ||
           typeof s.WebkitBorderRadius === "string" ||
           typeof s.KhtmlBorderRadius === "string" ||
           typeof s.MozBorderRadius === "string";
};

document.documentElement.className += isBorderRadiusSupported() ?
        " border-radius" : " no-border-radius";

2. Создавать из строки ноды под каждый уголок недешево, а зааппендить их в DOM еще дороже. Вставка каждого уголка это рефлоу блока, в который он вставляется. Выгоднее просто отдавать доп. разметку сразу в HTML. Задействовать доп. разметку будем в зависимости от класса, который мы выставили у элемента <html>.

.no-border-radius .corners .lt {
    // Стили для уголков
}

3. На текущий момент в Опере нет поддержки border-radius. Не стоит гонять балластный код ради неизвестного будущего. Поэтому отрываем -opera-border-radius: 4px; и соответствующую проверку в JS.

UPD2: Opera 10.50 pre-alpha поддерживает border-radius, причем без префикса. Ура!

12.05.2009

Gmail: Двоеточие в id-шнике

Продолжение статьи «Особенности верстки Gmail».

Мой коллега Иван Широков заметил, что все id-шники в верстке Gmail начинаются с двоеточия.

Хочу поделиться с вами своими соображениями, зачем это может быть сделано.

Во-первых, чтобы нельзя было (даже по ошибке) навесить стили для такого id-шника, потому что #:my {color: red;} не работает. Своеобразная защита, которая как бы подчеркивает, что id-шник используется только в яваскрипте.

Во-вторых, и в главных, чтобы элемент не был доступен по идентификатору в глобальной области видимости (global namespace). Когда мы пишем <div id="my">test</div>, этот дивчик становится доступен через идентификатор my в глобальной области видимости. То есть alert(my.tagName) выдаст «DIV» (сюрприз, сюрприз!). А если писать с двоеточием <div id=":my">test</div>, то уже хренушки — нет такого идентификатора в глобальной области видимости. При этом элемент по-прежнему можно достать через document.getElementById(':my'). На самом деле это очень круто, так как уменьшается вероятность коллизии в глобальной области видимости.

Все это лишь мои догадки. А вы что думаете?

24.09.2008

Ссылка цветом текста

Задача: сделать ссылки цветом текста. При этом в разных блоках на странице цвет текста может меняться.

Сначала я указал цвет ссылки отдельно для каждого блока.

body {color: black;}
a.glossary {color: black;}
#shurum, #shurum a.glossary {color: red;}
#burum, #burum a.glossary {color: green;}

Потом я подумал, что ведь цвет ссылки можно наследовать от блока.

body {color: black;}
a.glossary {color: inherit;}
#shurum {color: red;}
#burum {color: green;}

Радости моей не было предела, пока я не открыл страницу в IE. Фак! Оба осла (6 и 7) не поддержали мою гениальную задумку и ни хрена не пронаследовали цвет. Тогда я достал большую базуку и замочил IE вдребезги пополам написал маленький экспрешн.

a.glossary {color: expression(this.parentNode.currentStyle.color);}

Лучше, конечно, написать одноразовый экспрешн (не стал здесь так делать для наглядности).

30.06.2008

JavaScript + CSS

Задача: Подружить JavaScript и CSS, чтобы при отсутствии JavaScript применялись немного другие стили.

Предположим, что у нас есть блок <div id="block">блок</div>, который изначально должен быть скрыт и появляться по нажатию на псевдоссылку <span id="link">псевдоссылка</span>. Если же джаваскрипта нет, то блок должен показаться сразу, а псевдоссылка спрятаться с глаз долой.

Вариант 1. С использованием тега <noscript> (олд скул)

<style type="text/css">
    #block {display: none;}
</style>

<noscript>
    <style type="text/css">
        #block {display: block;}
        #link {display: none;}
    </style>
</noscript>

Это работает, но приходится создавать отдельный кусок стилей. К тому же валидатор ругается что есть сил, поскольку <style> запрещен внутри <noscript>, а <noscript> запрещен внутри <head>. Плохой способ, не рекомендую так делать.

Вариант 2.

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

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

Вариант 3.

Как можно побороть моргание блока? Я использую такое решение. В теге <head> добавляем простую строчку:

<script type="text/javascript">document.documentElement.className = "js";</script>

Если джаваскрипт включен, элементу <html> присвоится класс js. Что важно, это произойдет до загрузки контента. Теперь можно написать такие стили:

#link {display: none;}

.js #link {display: inline;}
.js #block {display: none;}

21.03.2008

CSS: line-height

Как-то я долго мучился с line-height.

Задавал его в em и процентах у body и были жуткие глюки с наследованием.

Я уже было отчаялся и решил жахнуть стиль для звездочки:
* {line-height: 1.4em;}

Но тут, коллега подсказал мне, что line-height нужно указывать без единиц измерения.

Оказывается, если указывать line-height в em или %, то при наследовании браузеры не пересчитывают line-height в зависимости от размера шрифта текущего элемента. Из-за этого у меня в <h1> слипались строчки.

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