这篇文章由 CSSKarma 的 Chris Coyier 和 Tim Wright 共同撰写
传统的日历是页面上带编号的方格。 作为一名网页设计师,您可能直接使用表格,我不会责怪您。 但是,表格有时很难塑造成形。 我内心纯粹的 CSS 就会恼火,当我设置表格(或单元格)的宽度时,它决定自己知道得更多,并根据自己的想法增大或缩小。
您可以使用纯 CSS 来处理日历样式,我觉得它在语义上与表格一样有意义。 日历是什么,如果不是一列有序的天数? 通过使用 CSS,我们甚至可以做一些很酷的事情,比如使用 em 来进行所有尺寸调整,这样我们的日历布局就会是弹性的。 也就是说,当浏览器中调整文本大小时,日历的宽度和高度都会随之变化,同时极大地提高可访问性。
我们来看看吧?
三个有序列表
从语义上讲,月历不是单个有序列表,而是三个。 显然,月份的所有日期都是一个有序列表。 但月份并不总是从星期日开始,在星期六结束,因此在网格的开头和结尾,那些“填充”天数更有意义地成为自己的列表。 看一看
<ol class="calendar" start="6">
<li id="lastmonth">
<ol start="29">
<li>29</li>
<li>30</li>
</ol>
</li>
<li id="thismonth">
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
<li>11</li>
<li>12</li>
<li>13</li>
<li>14</li>
<li>15</li>
<li>16</li>
<li>17</li>
<li>18</li>
<li>19</li>
<li>20</li>
<li>21</li>
<li>22</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>
</ol>
</li>
<li id="nextmonth">
<ol>
<li>1</li>
<li>2</li>
</ol>
</li>
</ol>
以及完全样式化的 CSS
/*
* CSS Calendar
* Tim Wright
* Chris Coyier
-----------------------------*/
* {margin:0;padding:0;}
body {font:1em/1.4 Verdana, Arial, Helvetica, sans-serif;
background: url(images/bg.jpg) top center no-repeat #545454;}
body * {display:inline;}
ol.calendar {width:52em;margin:0 auto;display:block; min-height: 200px;
background: url(images/tl.png) top left no-repeat; padding: 12px 0 0 20px;}
li {list-style:none;}
p.link {text-align:center;display: block;}
h1 {display: block; width: 200px;height:76px;
background:url(images/july.png);text-indent:-9999px; margin: 15px auto; }
/*
* Day styles
-------------------------*/
li li {width:6em;height:6em;float:left;margin:.2em; padding:.2em;overflow:auto;
background: url(images/day-bg.png) bottom right no-repeat; }
/*
* Day content (UL/OL & P)
-------------------------*/
li li p {font-size:.7em;display:block;}
li li ol {width:auto;}
li li ul li,
li li ol li {font-size:.7em;display:block;height:auto;width:auto; background: none;
margin:0;padding:.2em 0;float:none;}
/*
* Holiday class
-------------------------*/
li li.holiday { }
/*
* Inactive months
-------------------------*/
li#lastmonth li,
li#nextmonth li { background: url(images/day-bg-inactive.png);}
这里要注意一些重要事项。
有序列表会生成自己的编号,因此从技术上讲,我们可以利用这一点并使用它来自动对日历进行编号。 但是,以这种方式进行定位会有点棘手,而且无论如何您都需要在每个列表项中添加一些内容(至少要添加一个 ),以使其在所有浏览器中正确呈现。 因此,最好将列表样式设置为 none,并将日期数字直接放在列表项中。 由于这一点,当 CSS 关闭时,我们会得到以下结果
1. 1
2. 2
3. 3
…
等等。
这不是世界末日,但因为我们希望即使没有 CSS,我们的日历也尽可能好,所以您可能需要考虑使用无序列表,这样您就可以获得项目符号。
另外,请注意 <ol> 元素中的“start”属性。 这使您的列表可以从除“1”以外的数字开始。 此元素最近已弃用。 这样做是因为列表并不总是基于十进制的,它们可能是字母或罗马数字,或者其他任何有序列表可以表示的东西。 但是,没有 CSS 替代方案,因此只能使用弃用元素。(注意:如果您希望出于验证原因将此 start 属性保留在代码之外,Piotr Petrus 提供了一种使用 javascript 的方法。)
跨浏览器问题
也许更有趣的是,我们在这种标记中遇到的跨浏览器问题。 我们在这里的目标是一个直观的网格,所以我们使用的是浮动块。 但列表默认情况下是块级元素,因此为了使所有块都位于同一个网格中,从技术上讲,这些块需要彼此直接叠放在一起才能看起来正确。 当我们创建它时,除了(有趣的是)Firefox 2 之外,所有浏览器都正确地处理了它。 但是 Firefox 3 却正确地处理了它。
Tim 通过将页面上的所有元素设置为内联来欺骗 Firefox 2 服从
body * {display:inline;}
然后根据需要将元素设置回块。
关于在 body 内的所有元素上显示内联的一个有趣注意事项……Google Analytics 代码位于 body 内的 <script> 标签中(默认情况下设置为 display:none),在 <script> 上显示内联将显示您嵌入的 JavaScript。 这实际上是 Firefox 中的一个不错补充,尤其是在编写教程并希望显示您的 CSS 或 JavaScript 时。 您可以实际显示使页面运行的嵌入式 CSS/JS 代码,非常酷。
在这种情况下(JS 嵌入在 body 中的某个位置),您可能希望将日历包装在一个 <div> 中并使用 div *{display:inline;}。
我们发现的另一个奇怪问题是,display:inline 和 float:left 的组合会将每个有序列表项的计数器重置为零(仍然不知道为什么——而且只在 FF3 中测试),因此您最终会得到一个很长的零列表。 这很奇怪,但由于我们删除了列表样式,所以这不是什么大问题。
当然,任何网页都少不了 IE 的问题。 在 IE 6&7 中,每个日期内的 OL 和 UL 的边距会稍微挤压文本,这没什么大不了的,但需要注意。
最后的想法
我们并不建议您抛弃基于表格的日历,转而使用纯 CSS 解决方案。 我们只是想表明这是可以做到的,如果您选择这样做,这种方法甚至还有一些特定的优势。 要了解另一种方法,请查看 Rob 关于 CSS 日历样式的最新文章。 总的来说,这个日历比我们预期的花费的时间要长,但它最终还是做得很好,并且是一个很好的方法,可以证明您可以使用正确的 CSS 和一些语义标记,让任何东西都按照您想要的方式显示。
我们的示例使用背景图像来表示日期。 由于设计的弹性特性,这些背景图像需要比方框大得多。 许多较新的浏览器提供“缩放”功能,这使得这一点变得没有必要,但为了兼容所有人,这是最佳实践。
伙计们,这真的很有用。 谢谢你们 :)
没有什么比 CSS-Tricks 更能让人感到“鼓舞人心”了!
我不喜欢经典网页设计中的日历,但您的技巧非常酷,谢谢 :)
这很不错.. 我是在您的推文提要中看到的.. 谢谢
不错的技巧! 如果您需要将事件数据显示为列表,但也能够将相同的标记转换为网格视图,这将非常有用。 不过,如果您主要表示网格,我会认为表格在语义上并不比它差(甚至更优),因为网格中日期的位置受其所属的星期(行)和日期(列)的交点约束。
抱歉,伙计们,这只是一个很好的概念证明,但日历是一个有两轴的表格,分别是星期和日期。 修改有序列表固然很好,但为什么要这样做呢?毕竟表格已经可以轻松地实现您的需求。
特别是关于 body * {display:inline;} 的问题(虽然您为什么没有选择 ol.calendar * {display:inline;} 我不明白),以及必须在脚本元素上添加 display:none(w3c 验证器在您的示例中不喜欢这一点)。
我必须说,日历的弹性让我很感兴趣,我只想知道表格是否也能做到这一点(当然,您可以通过 em 来设置表格的宽度)。
好主意,但让我们加一个免责声明,说没有理智的人会这样做。
我最近不得不使用不同的视图(每月、每周和每天)来实现一些相当复杂的事件日历。
我发现“rowspan”和“colspan”属性在允许事件跨越多个时间增量(天、小时等)方面非常有用。 我非常相信,使用列表来实现这一点将是一场噩梦。
我同意其他一些评论者的观点,即表格在样式化日历方面确实更具有语义性——尤其是在网格格式中,其中两个轴具有语义含义。 使用 ROWSPAN、COLSPAN、THEAD 和 TH 提供了很大的灵活性,以及语义意义。
哇。 我从未想过会支持使用表格,但我认为它提供了最富语义性的关系。
撇开所有这些不谈,我认为您确实非常出色地实现了基于列表的日历! 赞赏,谢谢分享!
我同意 Phil 的观点,如果 CSS 被关闭,就没有任何意义了
但这项技术可以非常有用,适用于许多其他东西,再次感谢 Chris 和 Tim 的出色工作。
继续努力。
让我们不要过度使用列表,好吗? 表格在日历中确实有意义…
哇,这太棒了,伙计!
太棒了!
我只是不明白为什么表格会被过度使用。我喜欢这个概念,而且“实践出真知”,但它确实有很多代码。并不是说这不是个好主意。坦白地说,我只是无法让表格按我的意愿行事,它不会静止或“玩死”,如果你明白我的意思。我实际上正在将基于 CSS 的日历整合到我的即将推出的 Datebook 应用程序中。这给了我所需的代码资源来创建一个更好的全月日历。
日历就是表格。故事的终结。这种“让我们重新发明一切”的嬉皮士式废话现在已经过时了。