Заметки за апрель 2012 года

Сетка из блоков фиксированных размеров

При вёрстке сетки из однотипных объектов (неважно с помощью плавающих блоков или строчных блоков) возникает проблема с отступом у последнего блока в конце строки.

Допустим, контейнер имеет ширину 350px, блок – 80px и зазор между блокам – 10px.

Блоки не поместились в отведённые им размеры

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

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

margin-right: -10px;
position: relative; zoom: 1; /* контейнеру нужен hasLayout */

Для зазора между блоками появилось место в контейнере

Если у контейнера есть фон, то стоит создать дополнительную обертку без фона. Увеличив ширину можно получить нежелательный эффект. А избавляться от него с помощью overflow: hidden не всегда бывает приемлемо.

Дополнительная обертка, чтобы не затрагивать фон контейнера

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

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

Управляем скоростью вызова функций

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

Фреймворк Underscore предоставляет два вспомогательных метода для этих целей.

function debounce(func, wait, immediate) {
    var timeout;
    return function () {
        var context = this, args = arguments;
        var later = function () {
            timeout = null;
            if (!immediate) {
                func.apply(context, args);
            }
        };
        if (immediate && !timeout) {
            func.apply(context, args);
        }
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
    };
}

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

$(window).on("resize", debounce(function () {
    console.log("resize event");
}, 1000));

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

$(window).on("resize", debounce(function () {
    console.log("resize event");
}, 1000, true));

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

function throttle(func, wait) {
    var context, args, timeout, throttling, more, result;
    var whenDone = debounce(function () {
        more = throttling = false;
    }, wait);
    return function () {
        context = this;
        args = arguments;
        var later = function () {
            timeout = null;
            if (more) {
                func.apply(context, args);
            }
            whenDone();
        };
        if (!timeout) {
            timeout = setTimeout(later, wait);
        }
        if (throttling) {
            more = true;
        } else {
            result = func.apply(context, args);
        }
        whenDone();
        throttling = true;
        return result;
    };
}

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

$(window).on("resize", throttle(function () {
    console.log("resize event");
}, 1000));

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

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

SPF и DomainKeys для «чайников»

В заголовках писем от CMS моего сайта я вижу такую строку

Authentication-Results: mxfront10h.mail.yandex.net; spf=softfail (mxfront10h.mail.yandex.net: transitioning domain of noteskeeper.ru does not designate 46.254.17.128 as permitted sender) smtp.mail=www-data@noteskeeper.ru

Казалось бы, правильный IP-адрес и домен, а принимающий сервер пишет, что не дозволенный отправитель. Я начал разбираться с этим вопросом и открыл для себя SPF (Sender Policy Framework), DomainKeys и DKIM (DomainKeys Identified Mail).

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

SPF

Особенностью моей ситуации было то, что вся почта обслуживается сервисом Яндекс.Почта для домена. Но и сам хост также может отправлять письма.

У меня уже была указана spf-запись, которая приводится в инструкции по настройке «Почты для домена». Мне нужно было как-то добавить IP адрес хоста в разрешенные отправители почты. Это на деле оказалось не так уж сложно:

@ IN TXT "v=spf1 a include:_spf.yandex.ru -all"

Эта конструкция предписывает считать хост, обозначенный записью A домена, как разрешенный и далее получить ещё дополнительные правила у Яндекса.

Синтаксис и масса других примеров описаны в документации к проекту Sender Policy Framework.

dkfilter

Я решил пойти дальше и настроить цифровую подпись всех писем, которые отсылаются с моего хоста. После недолгих поисков я нашел отличное решение для своей VPS под управлением Ubuntu — dkfilter. Не буду пересказывать принцип настройки этого фильтра. Автор достаточно подробно и точно описал, что нужно сделать.

От себя добавлю несколько изменений, которые мне потребовалось внести.

Конфигурация фильтра

Мне потребовалось руками указать домен noteskeeper.ru, так как скрипт фильтра не мог его правильно определить. Подозреваю, что это последствия какой-то ошибки конфигурирования системы. Пока я остановился на этом варианте.

Ещё я указал метод генерации подписи simple вместо nofws. Если я правильно понял, то это только влияет на то, как будет преобразован текст письма с заголовками прежде, чем будет вычислена сигнатура.

DNS-запись

В инструкции указано, что открытый ключ домена нужно вводить в формате

selector1._domainkey IN TXT "k=rsa; p=MHwwDQYJK ... OprwIDAQAB; t=y"

Из RFC 4870 я узнал, что вместо селектора selector1 может быть любая строка. Главное, чтобы такой же селектор был указан в конфигурации dkfilter.

Потом выяснилось, что тег t=y обозначает режим тестирования. Когда тестирование будет закончено, этот тег стоит убрать из записи.

sendmail

Чтобы посылать тестовые сообщения я использовал sendmail. Они, к сожалению, шли в обход фильтра. В FAQ приведены настройки, которые нужно добавить в конфигурацию postfix.

Валидируем подпись домена

Гугл доверяет почте, отправленной с хоста noteskeeper.ru

Received-SPF: pass (google.com: domain of mista_k@noteskeeper.ru designates 46.254.17.128 as permitted sender) client-ip=46.254.17.128;
DomainKey-Status: good
Authentication-Results: mx.google.com; spf=pass (google.com: domain of mista_k@noteskeeper.ru designates 46.254.17.128 as permitted sender) smtp.mail=mista_k@noteskeeper.ru; domainkeys=pass header.From=mista_k@noteskeeper.ru
Received: from noteskeeper.localdomain (localhost.localdomain [127.0.0.1])
    by noteskeeper.localdomain (Postfix) with ESMTP id 997CD2A78003
    for <mistakster@gmail.com>; Mon,  9 Apr 2012 12:57:55 +0400 (MSK)
DomainKey-Signature: a=rsa-sha1; h=Received:To:Subject:Message-Id:Date:From
    b=dQHTHUU8sQCij/EDk+sv5aR8SJRuI51BBgM7LCxfihd1xNm33zUbvGo6/Csk
    spYLkwaAGGINjETWGwe0qaCZJ7AEkyZYbmNcLG2xewRGZCXyIjiygZIVyqqE
    L63lhDnwEzkG5aYyxPOQciVwmWuBExBTwNFKX0Q7p8s4eWUmyIM=;
    c=simple; d=noteskeeper.ru; q=dns; s=email

Подпись успешно проверена.

Комментарии к заметке: 9