Верстаем HTML/CSS календарь

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

Готовых скриптов в Сети много, разной степени навороченности и крутизны, но мне нужно было что-то простое и я не хотел использовать javascript, поэтому решил сделать сам. И вот что у меня получилось:

HTML/CSS календарь

Давайте посмотрим как делается симпатичный календарь с помощью HTML/CSS.
Как видно из скриншота, было довольно много ограничений, в основном по размерам. Фактически пришлось втиснуть весь месяц в кубик размерами 200х150 пикселей. Так как календарь верстался для уже готового сайта, то простора для творчества было совсем мало.

Начнем с кода. Мне показалось логичным сделать календарную структуру с помощью definition list.

Definition term я оставил пустым, так как заголовок был задан в бэкграунде. Месяц, названия дней недели и числа я описал списками, вложеными в definition description.

Собственно весь HTML:

<dl>
<dt> </dt>
<dd>
<p class="month">May 07</p>
</dd>
<dd>
<ul class="week">
<li>S</li>
<li>M</li>
<li>T</li>
<li>W</li>
<li>T</li>
<li>F</li>
<li>S</li>
</ul>
</dd>
<dd>
<ul class="days">
<li><а hrеf="#"> </a></li>
<li><а hrеf="#"> </a></li>
<li><а hrеf="#">1<span>Content 1</span></a></li>
<li><а hrеf="#">2<span>Content 2</span></a></li>
<li><а hrеf="#">3<span>Content 3</span></a></li>
<li><а hrеf="#">4<span>Content 4</span></a></li>
<li><а hrеf="#">5<span>Content 5</span></a></li>
<li><а hrеf="#">6<span>Content 6</span></a></li>
<li><а hrеf="#">7<span>Content 7</span></a></li>
<li><а hrеf="#">8<span>Content 8</span></a></li>
<li><а hrеf="#">9<span>Content 9</span></a></li>
<li><а hrеf="#">10<span>Content 10</span></a></li>
<li><а hrеf="#">11<span>Content 11</span></a></li>
<li><а hrеf="#">12<span>Content 12</span></a></li>
<li><а hrеf="#">13<span>Content 13</span></a></li>
<li><а hrеf="#">14<span>Content 14</span></a></li>
<li><а hrеf="#">15<span>Content 15</span></a></li>
<li><а hrеf="#">16<span>Content 16</span></a></li>
<li><а hrеf="#">17<span>Content 17</span></a></li>
<li><а hrеf="#">18<span>Content 18</span></a></li>
<li><а hrеf="#">19<span>Content 19</span></a></li>
<li><а hrеf="#">20<span>Content 20</span></a></li>
<li><а hrеf="#">21<span>Content 21</span></a></li>
<li><а hrеf="#">22<span>Content 22 Blah blah many content much more content</span></a></li>
<li>23</li>
<li>24</li>
<li>25</li>
<li>26</li>
<li>27</li>
<li>28</li>
<li>29</li>
<li>30</li>
<li>31</li>
</ul>
</dd>
<dd id="descr">Point cursor to some date</dd>
</dl>

Здесь я думаю стоти прояснить один момент. Внутри каждого элемента списка есть ссылка, текстом которой является само число и там же находится span, внутри которого находится текст подсказки, которая нужна нам при наведении мышки. У span‘а изначально прописано свойство display:none, чтобы его не было видно.

Так как span находится в ссылке (как Ленин в свое время :) ), то мы можем поменять ему свойства на событии hover. Все что нам нужно это поменять свойство display на block. Ну почти все. Этот способ называется Pure CSS Popups, который описал небезызвестный Eric Meyer.

Но рыжий Эрик схитрил(?) и не описал у себя баг, из-за которого способ не работает в IE6… Но Гугль как всегда рулит и я нашел решение этой проблемы. Суть его сводится к тому, что в a:hover ОБЯЗАТЕЛЬНО нужно указать какое-либо свойство, которое не присутствует в a:link, a:visited и a:active. Любое кроме color. Я выбрал text-indent: 0. Ура, заработало!
Есть еще один момент. Так как мне нужно было абсолютно позиционировать текст подсказки внутри блока, то для definition list я задал position:relative, не указывая явно top и left, а для span с подсказкой position:absolute и координаты.

Всем элементам списка я задал фиксированую ширину и высоту и float:left. С размерами подогнал так, чтобы в одну строку влезали только 7 чисел.

Смотрим на стили:

dl{
width: 214px;
height: 182px;
background: url("schedule-bg.gif") left top no-repeat;
margin: 0 auto;
position:relative;
}
dt{
height: 34px;
}

dd ul{
margin: 0;
}

dd ul li{
list-style: none;
margin: 3px 1px 1px 1px;
width: 26px;
height: 12px;
line-height: 12px;
float: left;
text-align: right;
cursor: pointer;
font-size: 12px;
}
dd ul li a{
display:block;
width: 26px;
height: 12px;
text-decoration: none;
color: #0000FF;
}

dd ul li a span{
display:none;
}

ul.days li a:hover{
color: #FBC500;
text-indent: 0; /*DO NOT REMOVE THIS OTHERWISE HOVER WILL NOT WORK IN IE6!*/
}

ul.days li a:hover span{
display: block;
position: absolute;
left: 5px;
top: 150px;
width: 200px;
height: 23px;
overflow: hidden;
text-align: center;
background: #5c68ba;
color: #FFFFFF;
text-decoration: none!important;
}
.month{
font-size: 12px;
font-weight: bold;
text-align: center;
}

.week li{
border: none;
font-weight: bold;
margin-left: 1px;
margin-right: 2px;
}

.days{
margin-left: 5px;
height: 98px;
*height: 85px;
width: 205px;
}

#descr{
clear: both;
color: #FFFFFF;
font-size: 12px;
text-align: center;
padding-top: 3px;
height: 23px;
}

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

Все, вроде бы ничего не упустил. Рабочий пример можно посмотреть и забрать.

Верстал я все это дело в XML/XSL, вот так выглядит тэмплэйт:

<dl>
<dt> </dt>
<dd>
<p class="month">
<xsl:value-of select="$SHARED/MONTHS/LIST[@ID= $month]/@NAME"/>
</p>
</dd>
<dd>
<ol class="week">
<xsl:for-each select="$SHARED/WEEK/ITEM">
<li><xsl:value-of select="text()"/></li>
</xsl:for-each>
</ol>
</dd>
<dd>
<ol class="days">
<xsl:for-each select="$SHARED/MONTHS/LIST[@ID= $month]/ITEM">
<li>
<a>
<xsl:if test="@NUM = $date">
<xsl:attribute name="class">currentday</xsl:attribute>
</xsl:if>
<xsl:attribute name="hrеf"><xsl:value-of select="@HREF"/></xsl:attribute>
<xsl:value-of select="@NUM"/>
<span><xsl:value-of select="text()"/></span>
</a>
</li>
</xsl:for-each>
</ol>
</dd>
<dd id="descr"><xsl:value-of select="$SHARED/MONTHS/DESCR"/></dd>
</dl>

На пути к XML нодам не обращайте внимания, особенности платформы.

This entry was posted in CSS, HTML, XSLT. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

27 Responses to Верстаем HTML/CSS календарь

  1. Jurij Burkanov says:

    Круто. Респект и уважуха!
    Код стащил для дальнейшего (может, пригодится когда) использования. :)

  2. neutrino says:

    2 Jurij Burkanov

    спасибо :)

  3. LeshaOgonkov says:

    так и не уловил смысла использования списка определений…

  4. Виктор says:

    Супер!
    Вот только когда переставляешь 1е число и добавляются пустые элементы списка надо с них убирать ссылку, а то указатель над ними появляется.

  5. Gorik says:

    [quote post="95"]так и не уловил смысла использования списка определений…[/quote]
    +1

    А вообще круто, спасибо огромное

  6. neutrino says:

    [quote comment="409"]так и не уловил смысла использования списка определений…[/quote]

    Ну если подходить к вопросу с точки зрения семантики, то календарь это список определений – dl, месяц это термин/определенный период, соответственно dt, а дни это описание/значение для термина, выраженое через список, соответственно dd.

    Вроде логично, нет?

  7. neutrino says:

    [quote comment="413"]Супер!
    Вот только когда переставляешь 1е число и добавляются пустые элементы списка надо с них убирать ссылку, а то указатель над ними появляется.[/quote]

    Да, верно подмечено.

  8. Zigzag says:

    не зачет! календарь – есть колссические табличные данные и должен верстаться таблицей.

  9. Zigzag says:

    а месяцем будет заголовок таблицы

  10. neutrino says:

    [quote comment="424"]не зачет! календарь – есть колссические табличные данные и должен верстаться таблицей.[/quote]

    С какой же это радости “календарь это классические табличные данные”? В данном случае календарь это список дней.

    [quote comment="424"]а месяцем будет заголовок таблицы[/quote]

    А годом будет заголовок заголовка таблицы?

  11. Zigzag says:

    [quote post="95"]С какой же это радости “календарь это классические табличные данные”? В данном случае календарь это список дней.[/quote]

    Да с той самой, что календарь есть таблица с заголовком в виде месяца и днями недели в виде заголовков столбцов. Почитайте намного материала по семантике.

    [quote post="95"]А годом будет заголовок заголовка таблицы?[/quote]

    А это уже не имеет значения, хоть в год возьмите.

  12. neutrino says:

    Zigzag, ссылки в студию.

  13. annoymouse says:

    Всё-таки, zigzag, имхо, прав. Календарь – классический случай табличных данных, хотя бы потому, что исходные данные для календаря – множество состоящее из пар вида: (неделя, день недели).

  14. neutrino says:

    [quote post="95"]исходные данные для календаря – множество состоящее из пар вида: (неделя, день недели)[/quote]

    Ну какая же это пара? По логике это список, подсписок.

  15. Flack says:

    Вообще грят, что форич в xslt — зло.

  16. neutrino says:

    [quote comment="446"]Вообще грят, что форич в xslt — зло.[/quote]

    Хм, интересно. Я xslt исключительно сам учил. Было бы интересно послушать что используют вместо.

  17. rmaksim says:


    если делать аналогично как в ссылке, то получится что-то типа

    и соотв стили

    .месяц01 { width: 52px; }
    ...
    .месяцХХ { width: (x-1)*26px; }

    где X день с которого начинается 1-е число в данном месяце
    короч разберешся и доработаешь под себя… :)))

  18. lusever says:

    Так же сделал в начале года на http://tvoibar.ru/ .

    Списки это хорошая идея.

  19. neutrino says:

    [quote post="95"]Так же сделал в начале года на http://tvoibar.ru/ .[/quote]

    Получилось неплохо :)

  20. Flack says:

    Тупо apply-templates.

  21. neutrino says:

    [quote comment="492"]Тупо apply-templates.[/quote]

    Не, так беспонтово. Для создания списков вобще и менюшек в частности for-each – очень удобная штука.

  22. Flack says:

    Речь о производительности, а не о понтах.

  23. neutrino says:

    2 Flack

    Леша, это оборот речи такой :) Согласен, не самый удачный. О каких понтах может идти речь если xsl-код никто кроме тебя не видит?
    Я собственно поэтому тебя и спросил в чем разница.
    То есть получается что apply-templates срабатывает быстрее чем for-each?

  24. Flack says:

    меня научили так :)
    возможно, это особенность трансформатора, а возможно и такая же неписаная истина как и // в xpath.

  25. jahson says:

    Календарь – таблица. Особенно в случае, когда есть названия дней – они так и просятся в th.

  26. neutrino says:

    [quote comment="580"]Календарь – таблица. Особенно в случае, когда есть названия дней – они так и просятся в th.[/quote]

    Смотрите мои комментарии выше.

  27. Бассейныч says:

    спасибо автору за статью. Очень полезно

Leave a Reply

Your email is never published nor shared. Required fields are marked *

*

You may use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>