有史以来最糟糕的名字,但我一直在努力给它命名,这似乎很合适。 这是最终结果
它涵盖了我认为有趣的一些内容
- jQuery 1.4 的新元素创建语法,它非常酷,我们还没有介绍
- 编写一个小型插件以防止重复代码(并保持 jQuery 的精神)
- 谈到我开始考虑的面向对象的 CSS
目标
我们这里有一些内容框。 目标是当您将鼠标悬停在它们上时,它们会变暗,并且链接会出现在它们的正中心。 我意识到这对很多东西来说不是理想的 UI 选择。 使事物在您将鼠标悬停在它们上时变得不可读是一种不寻常的设计选择。 但在某些情况下它可能是完美的。 故事寓意:不要根据演示做出草率的判断。
HTML
只是一个包含一些文本的 div...
<div class="widget widget-one rounded">
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
</div>
您可能想要做的是在每个小部件中包含一个超链接,该链接将指向与我们将在 JavaScript 中添加的链接相同的位置(可降级性)。 再次强调,这只是一个演示,在实际场景中情况会有所不同。
CSS
我称我们的小方框为“小部件”。 请注意,我为 div 包装器指定了一个名为 widget 的类。 这是基本的小部件
.widget {
width: 300px;
padding: 20px;
border: 1px solid #999;
margin: 0 20px 20px 0;
float: left;
position: relative;
}
但请注意,在上面的实时演示和图像中,小部件具有圆角。 我们都知道如何在 CSS 中创建圆角。 存在标准border-radius以及它的姊妹供应商扩展。 为什么不直接将它们添加到 widget CSS 本身呢? 这就是面向对象的 CSS 的用武之地...
我的大脑和 CSS通常的工作方式是,我尝试使 HTML 尽可能干净和语义化。 我一直被教导说使用像“red”这样的 CSS 类名是一种非常糟糕的做法,因为“red”不是语义化的,是专门描述性的。 相反,您应该使用诸如“important”或“warning”之类的东西,因为如果您后来决定这些东西应该变成绿色而不是红色,那么您的“red”类就会令人尴尬地变得无关紧要。
面向对象的 CSS 颠覆了部分这种思维方式。 面向对象的 CSS 使用类名专门描述该“对象”(页面元素)的设计特征。 请注意,我还为小部件指定了一个名为“rounded”的类。 在我们的 CSS 中,rounded 类将是
.rounded {
-moz-border-radius: 20px;
-webkit-border-radius: 20px;
border-radius: 20px;
}
亵渎神明? 我过去也这么认为,但最近我非常喜欢这种方法。 页面上可能有 20 件事是“rounded”的。 现在我们只需要将 rounded 类名应用到它们中的每一个,它们就会变成圆角。 需要调整边框半径吗? 在一个地方调整它,所有圆角对象都会匹配。 如果不这样做,我们将在 CSS 中更新 60 个不同的位置。
这可能适合某些站点,而不适合其他站点。 这感觉像是一个逃避责任的说法,但确实如此。 也许对于拥有大量遗留内容的站点来说,这并不现实。 它可能非常适合拥有较少内容的新站点,在那里 CSS 几乎和 HTML 一样多。
JavaScript 最终将向我们的 Widget 应用一个新的 div,该 div 的作用是使 Widget 变暗。 我们将这个类称为“overlay”。 以下是它的 CSS
.overlay {
position: absolute; top: 0; left: 0; right: 0; bottom: 0;
background: url(../images/black75.png);
background: rgba(0,0,0,0.6);
text-align: center;
}
它使用 RGBa 为现代浏览器进行变暗(更灵活,可能会节省一个 HTTP 请求),并回退到一个 alpha 透明的 PNG(对于 IE 7)。 处理此问题的另一种方法是使用纯黑色背景颜色并使用常规透明度,但由于在该演示中我们将有“中间盒链接”位于叠加层内,并且我们不希望它也透明,因此这种方法效果很好。
jQuery JavaScript
快速重复一下我们的目标:当 Widget 被悬停时,我们希望将它变暗并在它的正中间添加一个链接。 在我们的演示中,我们有四个 Widget。 其中一些高度不同,因此我们需要对此进行调整。 每个 Widget 还显示不同的文本作为“中间按钮链接”,以及不同的 URL。 这意味着一些代码将不同,但很多代码会相同。 这需要进行一些抽象。 在 JavaScript 中,我们可以直接使用自定义函数,我们可以为每个 Widget 调用该函数。 但是,秉持 jQuery 的精神,让我们把它变成一个小插件。 这意味着我们将保持完整的 jQuery 特定功能,例如可链接性。
请注意,我们已经为每个 Widget 添加了一个唯一的类名。 这样我们就可以使用 JavaScript 中的该挂钩单独定位 Widget。 我们也可以使用 ID,这更有效率,但嘿,您可能在同一个页面上拥有两个使用相同文本和链接的 Widget。 使用相同的类名将在这种情况下有效,而 ID 则不会。 这是我们想要的抽象
$(function() {
$(".widget-one").middleBoxButton("Read More", "#read");
$(".widget-two").middleBoxButton("Go to the Store", "#store");
$(".widget-three").middleBoxButton("Continue", "#more");
$(".widget-four").middleBoxButton("Behold!", "#bazinga");
});
当然,“middleBoxButton”不是一个函数。 这正是我们要作为插件创建的。 以下是整个代码
var $el, $tempDiv, $tempButton, divHeight = 0;
$.fn.middleBoxButton = function(text, url) {
return this.hover(function(e) {
$el = $(this).css("border-color", "white");
divHeight = $el.height() + parseInt($el.css("padding-top")) + parseInt($el.css("padding-bottom"));
$tempDiv = $("<div />", {
"class": "overlay rounded"
});
$tempButton = $("<a />", {
"href": url,
"text": text,
"class": "widget-button rounded",
"css": {
top: (divHeight / 2) - 7 + "px"
}
}).appendTo($tempDiv);
$tempDiv.appendTo($el);
}, function(e) {
$el = $(this).css("border-color", "#999");
$(".overlay").fadeOut("fast", function() {
$(this).remove();
})
});
}
因此,当 Widget 被悬停时,会创建一个全新的<div>。 此 div 具有“overlay”和“rounded”类。 我们已经知道“rounded”是什么意思(OOCSS)。 我们也已经知道“overlay”是什么,它确保 div 的大小与 div 完全相同,方法是设置绝对定位以及将顶部、右侧、底部和左侧值都设置为零,并处理变暗。 但是,此时还没有对这个 div 进行任何操作。
然后我们创建一个锚链接。 我们赋予它文本和 href 属性,这些属性是我们为此目的显式传递给插件的。 然后我们将此链接附加到我们刚刚创建的 overlay div,然后将它们都附加到 Widget。 jQuery 1.4 的新元素创建语法使这个元素创建过程变得非常简洁。 这部分
$("<a />", {
"href": url,
"text": text,
"class": "widget-button rounded",
"css": {
"top": (divHeight / 2) - 7 + "px"
}
});
请注意,我将所有“键”(冒号之前的部分)都放在引号中。 大多数键在没有引号的情况下也能正常工作,但我遇到了 key “class” 在 IE 中无法正常工作的问题。 事实证明这不是一个 bug,只是“class”是 JavaScript 中的保留字,而且不加引号的做法是不好的。 事实证明,在使用像这样使用的类似 JSON 的语法时,对所有内容都加引号是好的做法。
由于我们的目标之一是链接出现在正中间,所以让我们来谈谈它。 水平居中很容易,overlay div 具有 text-align: center,所以这就完成了。 垂直居中有点棘手。 有 CSS 方法可以处理它,但没有一种方法是超级干净和简单的。 我们已经在使用 JavaScript 了,所以让我们利用它。 我们将测量 Widget 的高度,将其减半,并将链接向下移动该距离。 唯一有点笨拙的地方是值“7”。 您一定讨厌在硬编码这样的值的时候,实际上我的意思是“按钮高度的一半”。 问题是,当我设置其他属性时,我无法计算按钮的高度,因为它还不存在。 如果您有想法,请告诉我。 还要注意,Widget 的高度不是仅仅使用 .height() 函数计算出来的,而是通过使用该函数并添加顶部和底部填充来计算出来的。
悬停(鼠标移出)的回调函数只是将边框恢复为其原始颜色,并淡出(然后移除)overlay div。 完成!
这是一个非常酷的效果。
您不能使用 outerHeight() 来获取 Widget 的高度吗?
我认为您应该使用 innerHeight(),因为 outerHeight() 会返回包括填充和边框在内的高度,而 innerHeight() 会返回包括填充但不包括边框在内的高度。
抱歉,应该更清楚一点... outerHeight(false) 返回 height+paddingTop+paddingBottom。 可选参数决定是否包含边距。
你应该称之为“覆盖链接”。只是我的两分钱。
我认为这将非常适合在图像上叠加链接,就像 Flash 风格一样,例如在链接到视频的图像上隐藏播放按钮,直到用户将鼠标悬停在它上面。
哇
太棒了!
酷
很棒的文章,但我不同意“面向对象的 CSS”这个术语,因为它根本不是面向对象的。
面向对象主要意味着将数据和逻辑组合成一个单一实体,即对象。由于你的 CSS 不包含任何逻辑,它不是面向对象的,它只是一个简单的分组属性的数据结构,在许多编程语言中被称为“结构”。
这里也没有真正的继承、封装或多态性,因为你正在将多个类应用于你的元素。
我这么说不是因为我喜欢玩文字游戏。只是以这种方式使用这个术语可能会让人困惑。
查看这里的幻灯片和解释
http://ajaxian.com/archives/nicole-sullivans-object-oriented-css
这只是一个微不足道的例子。
这个术语有点可笑,但我对它有点改观了。我认为,大多数情况下,处理“真正的”面向对象事物的人不会做太多 CSS。而那些做很多 CSS 的人,并没有太多与这个定义相冲突的面向对象编程经验。随意嘲讽我这种类型转换。=)
你把“面向对象”这个词和“面向对象编程”搞混了。某些东西可以是面向对象的,而不一定与 OOP 范式直接相关。
我想也是。我承认我对这些技术/历史方面的知识并不多。但在很字面的意义上,这对我有意义。我们将关注各个“对象”本身。所以,如果一个“对象”想要变圆,它需要一个名为 rounded 的类名。如果它想要 200 像素宽,它可能需要一个名为“grid_3”的类名。如果它应该获取新闻块的属性,它应该具有“news”类。
它是将样式可能性带回 HTML 的想法。因此,在构建新的内容区域时,你可以使用这个大型工具箱来处理对象的属性。也许,你不必编写更多 CSS 来适应这种新的内容,而无需特定的挂钩。
面向对象的 CSS 是一种错误的名称,故事的结局。
理想情况下,处理你的“.rounded”困境的方法是创建一个名为“rounded”的 CSS 类,然后在 CSS 文件中将该类映射到需要它的语义元素。因此,如果侧边栏是圆形的,你将在 CSS 中将侧边栏设置为圆形,这就是这类信息存放的地方。
不幸的是,你无法在 CSS 中做到这一点,所以我们必须在将样式信息污染 HTML 或在 CSS 中重复自己之间做出选择。
Chris,
顺便说一下,谢谢
.outerHeight() 返回的高度包含填充和边框,以及必要时的边距。
不错的文章。非常有用。准备尝试一下!
这是我一直在玩的东西之一。很高兴有一个教程可以开始!谢谢!
巴兹加!:)
不错的效果,Chris。
太棒了!谢谢 Chirs!:)
如何使它与键盘和屏幕阅读器用户兼容?
你只需要在小工具内的文本中放置与插件应用的相同锚链接。实际上,你可以修改插件来查找它,将其移除,并在覆盖层中使用它。这取决于场景…
请把它弄成这样。还有一件事,如果 JS 被禁用,那么链接也不可访问。
很棒的东西,Chris!
Chris,
很棒的文章,像往常一样。你问我们是否有关于按钮高度中的“7”的想法。也许你可以将其作为选项传递给函数。这样你就可以为每个小工具更改它。
我认为它们都应该相同,所以将其作为参数传递我认为会比它值得的更加复杂。
非常好的效果,谢谢….
Anthropologie 以前在他们的网站上使用过这种效果,但不是黑色背景和文本,而是白色背景和图像。我不记得他们的中间框链接是否有 a:hover 事件——如果有的话,它一定很微妙,因为我花了很长时间才意识到点击实际链接与点击图像正方形本身有不同的效果。我认为 Target 也有类似的东西。我一直很好奇它是怎么做到的——干得好。
我只是在浏览代码,所以如果我忽略了什么,请原谅我,但弹出的按钮是<a>标签,它们的显示类型设置为内联,所以与其计算按钮在中间的正确偏移量,不如直接将覆盖层的行高设置为与它的高度相同,并让浏览器进行垂直居中?这样就可以不需要硬编码的“7”,不是吗?
是的,这可以行得通,除非在极端情况下锚链接太长而导致换行。
很高兴看到 OOCSS 被使用。作为概念和作为 http://wiki.github.com/stubbornella/oocss/ 中的实际构建块,OOCSS 对我所有的 CSS 项目来说都是一个真正的“神奇子弹”。当与 YUI 3 小工具定义的标记模型一起使用时,它真的很出色(你根本不需要 YUI,它只是一个模式):http://developer.yahoo.com/yui/3/widget/index.html#markup。添加一个结构良好的文件,即使在非常大的项目中,CSS 也变得极其可靠和可预测。
我不知道你如何找到时间发布新内容,但非常感谢你。
自从我开始使用以来,我一直以这种方式定义我的类,使用“rounded”等等。我认为它更简单,因为你可以在网站上为自己制定标准——这有助于我保持井然有序。
OOCSS = **级联**样式表,没什么新鲜事。
它似乎是新的“ajax”(实际上是 XMLHttpRequest 对象),但给它一个时髦的名称,看看它变成新的热门事物。
友好请求——Chris 老兄,在你的条目顶部而不是底部附近(或者两者都)放一个指向演示的链接。我知道,这很小。哇,我受不了滚动鼠标滚轮向下滚动几英寸:) 我知道。但是,你是我每天必看的网站,我每隔一天或更长时间就会查看你一次,但我的必看网站清单很长。每天都没有足够的时间浏览到清单的底部。因此,如果你的文章最初看起来很吸引人,我通常想先看看演示。这样,如果时间不够,我会把它标记起来,以后再回来深入阅读。只是一点想法。
除此之外都很棒。谢谢!
关于 7:你能在屏幕外构建/渲染锚点,然后获取它的高度,然后通过绝对定位将其移动到最终位置吗?(我还没试过,只是在脑海里想。)
我有一个更好的主意。追加链接和 div,但添加一个额外的隐藏类,在其中添加 { display: none; } 或 { visibility: hidden; }(我认为这两种方法在本例中都有效)。这样你的元素就存在了。接下来计算链接的高度,并通过减去高度重新定位顶部。然后快速淡入,你就设置好了。
请不要因为我忘记了 <code> 标签而对我大吼大叫,让我头疼。现在很早,我的咖啡机坏了。如果我能编辑我的评论,我会修正标签的。
我可能有点吹毛求疵:你是否应该考虑从 widget div 中获取 URL?当然,这是在没有提供 URL 时的一项额外服务。我认为这将是你提到的关于不同情况以及可能想要在文本中添加 URL 以进行降级(这对你的 SEO 也不会有太大影响)的补充。
无论如何:你的博客做得很好,继续努力。我也期待你下一个屏幕录像!
糟糕。你能帮我处理一下我之前评论中的错误吗?非常感谢(a)
看起来都很好。
不过我有一个建议。将边框颜色从 widget 中移除,添加/删除一个 CSS 类,而不是应用 CSS 边框颜色。
例如,addClass(“jquery-middleboxlinks-hover”);
嗨,
我喜欢我看到的,这是一个很好的演示。
顺便说一句:关于你在演示中使用的圆角边框,我知道演示在没有它的情况下也能正常工作,而且我知道你喜欢使用圆角边框,我在你的很多项目中都看到了它。
但是它在 IE 中仍然不能正常工作,而且由于我为那些要求 X 设计的客户工作,他们应该得到 X 设计,而不是使用其他浏览器来查看 X 设计,所以我不想使用圆角边框(至少现在)。
这是一个非常酷的效果,感谢分享!
在我看到这些例子之前,这对我来说并不简单,要实现中间盒子并同时保持易于操作的布局是一项艰巨的任务……干得好!