一个工作示例
http://jsfiddle.net/q4d9m/2/
更新: There seems to be a bug with Firefox 32 (Mac) 这意味着椭圆不会在 SVG 蒙版中呈现,这会导致反射失败...不要让我开始使用 Chrome 37.0.2062.120 (Mac)如果您将鼠标悬停在此答案脚下已实施示例中的任何图像上,则正在执行此操作。
— 2014 年 9 月 18 日。
解释基本原理
幻灯片由两个主要部分组成,一个视觉部分和一个交互部分。交互部分几乎保持静态,而视觉部分是动画的。在玩了很多之后,我扩展了最初的 HTML 结构(见上文),在幻灯片内容周围加入了一些额外的包装器。这允许单独的交互和视觉部分,并为其他有用的功能(例如垂直居中和反射)提供额外的灵活性。
<ul class="css-slider">
<li class="slide" tabindex="1" id="l1">
<span class="slide-outer">
<span class="slide-inner">
<span class="slide-gfx" id="s1">
<img src="photos/a.jpg" />
</span>
</span>
</span>
</li>
<li class="slide" tabindex="1" id="l2">
<span class="slide-outer">
<span class="slide-inner">
<span class="slide-gfx" id="s2">
<img src="photos/b.jpg" />
</span>
</span>
</span>
</li>
...
</ul>
现在,为了让任何系统实际表现得像幻灯片,您需要有一些方法来识别当前或焦点幻灯片。在这种情况下,我依靠:focus 来处理这种区别。您可能已经注意到上面添加了tabindex=“1”,这是为了将伪类:focus 应用于像<li> 这样的意外元素——这主要用于基于webkit 的浏览器,但也可以帮助其他代理.
简单地说,所有的幻灯片都堆叠在一起,当前聚焦的幻灯片以视口为中心并给出最高的z-index,聚焦幻灯片之前的幻灯片被平移到屏幕左侧,并且聚焦幻灯片之后的幻灯片被平移到屏幕右侧。需要注意的是,xy 平移只影响幻灯片的视觉内容,交互部分仍然层层叠叠,填满了整个视口区域,几乎......
我说几乎是因为为了在下一张和上一张幻灯片上触发焦点(通过鼠标或触摸),用户必须可以访问和点击部分交互层。使用left、right 和padding 的混合可以显示正确的区域,而不会移动视觉元素。
因此,随着当前聚焦的幻灯片发生变化,可访问的交互式图层区域也会发生变化。每次用户单击下一个或上一个箭头时,他们实际上都在关注相邻的 <li> 元素,而不是单击执行任何操作的链接。
了解有用
为了让它在 Webkit 浏览器上工作,需要使用 tabindex 属性,以便 :focus 伪类将在您用来表示幻灯片的任何基本元素上起作用。
由于所采用的技巧,幻灯片将以相反的 dom 顺序播放。
-
您可以使用选项卡导航幻灯片,但是,由于第 2 点,它会向后导航。如果您有 Mac,您可能需要 tweak your os settings 才能使用选项卡。
李>
由于 left、right 技巧可以暴露导航箭头,因此在向前导航时会出现轻微的视觉故障 - 您可以看到随后的前一个箭头快速动画到位。
因为此系统基于:focus 工作,所以只要失去焦点,幻灯片就会恢复到初始幻灯片,因此,子链接将无法在您的幻灯片中工作 - 除非您增强与 JavaScript 的交互。
我的演示使用了 SVG 背景图像,这些显然是可选的,并且不适用于旧版浏览器。
支持
- Firefox v26.0(Mac/PC ~ 很可能是更早的版本)
- Chrome v32(Mac/PC ~ 很可能是更早的版本)
- Safari v7(Mac/PC ~ 很可能是更早的版本)
- Opera v18(Mac/PC ~ 很可能是更早的版本)
- Internet Explorer 9+(PC)
IE7 和 IE8 甚至无法理解 :last-child 或 :nth-child 所以不,它确实不对他们有用。
添加了额外功能
在下面的演示中,您将看到一些 JavaScript 的蓬勃发展,它们要么有助于展示构造的功能,要么逐渐增强。仅用于演示的复选框应允许您启用或禁用某些功能。这些功能由简单的类应用:
-
.with-responsive-images ~ 强制图片自动调整大小的小技巧。
-
.with-selection-disabled ~ 防止用户拖动和突出显示。
-
.width-fade-in ~ 一开始就将幻灯片淡入。
-
.with-reflection ~ 为 firefox 和 webkit 启用反射。
-
.with-slide-zoom ~ 悬停时幻灯片将缩放到最大宽度。
-
.with-slide-float ~ 聚焦幻灯片将悬浮。
-
.with-slide-float-hover ~ 悬停时幻灯片会悬浮。
-
.with-shadow ~ 穷人的倒影。
请注意:反射插件依赖于任意标记属性。您必须为每个 .slide 添加唯一的 id,然后扩展 CSS 以将它们考虑在内。
CSS 分解
设置
好的,所以从这里开始是基本设置。首先,因为我的幻灯片是带有图像的,所以我设置了一些基本的图像样式,这都是可选的。
.slide-gfx img {
max-width: 600px;
max-height: auto;
border-radius: 20px;
box-shadow: 0 0 80px rgba(255,255,255,1);
}
滑块蒙版作为包装添加到整个幻灯片中,以防止在以全屏大小操作幻灯片时显示窗口滚动条。这又是可选的。
.css-slider-mask {
display: block;
overflow: hidden;
width: 100%;
height: 100%;
}
现在我们得到了滑块所需的实际设置。第一部分非常简单,除了display: none; 部分。这最初对所有人隐藏幻灯片,但后来被支持:nth-child 的浏览器覆盖。您的 <body> 元素很可能是第二个子元素,但您应该在使用它之前进行检查。
.css-slider {
list-style: none;
margin: 0;
padding: 0;
width: 96%;
height: 100%;
margin-left: 2%;
z-index: 1;
}
.css-slider {
position: relative;
display: none;
}
body:nth-child(2) .css-slider {
display: block;
}
幻灯片
接下来,我们开始讨论幻灯片的细节。由于不存在反转的General Sibling Selector (~),幻灯片的所有默认样式都代表未来(或下一个)状态。这是因为没有实际的方法来选择未来的幻灯片。
.css-slider .slide {
display: block;
position: absolute;
left: 40px;
top: 0;
right: 0;
bottom: 0;
padding-left: 0;
padding-right: 40px;
z-index: 100;
outline: 0; /* kill the focus rect! */
}
同样,默认情况下,我们设置前进箭头的样式,然后在以后覆盖当前和过去的幻灯片。
.css-slider .slide {
background: url('arrow-right.svg') no-repeat right center;
background-size: 25px auto;
}
.css-slider .slide:hover {
background-image: url('arrow-right-hover.svg');
cursor: pointer;
}
现在是重点幻灯片,这里的关键项目是:focus(我已经解释过)和:last-child,但我没有。使用最后一个孩子而不是第一个孩子,因为我们必须再次向后工作(都是由于缺少反向 General Sibling Selector~)。为什么需要任何一个孩子,以便我们可以在没有当前焦点(即页面加载时)时“聚焦”初始幻灯片。
.css-slider .slide:target,
.css-slider .slide:target:hover,
.css-slider .slide:focus,
.css-slider .slide:focus:hover,
.css-slider .slide:last-child,
.css-slider .slide:last-child:hover {
left: 40px;
right: 40px;
padding-left: 0;
padding-right: 0;
background: transparent;
z-index: 101;
cursor: default;
}
现在我们需要影响所有滑入过去的幻灯片。我之前避免提及:target 伪类,基本上这已经实现以支持“跳转导航”。我不会歌颂“跳跃导航”的原因有两个:
- 它部分由 JavaScript 提供支持。
- 它依赖于 #hash 或 #fragment 值,由于历史状态的创建可能会影响您网站的可用性。
无论如何,选择过去幻灯片的技巧取决于General Sibling Selector。以下构造基本上意味着 选择您在具有 :focus 的 .slide 之后找到的 .slide 。
.css-slider .slide:target ~ .slide,
.css-slider .slide:focus ~ .slide {
padding-left: 40px;
padding-right: 0;
left: 0;
right: 40px;
}
.css-slider .slide:target ~ .slide,
.css-slider .slide:focus ~ .slide {
background: url('arrow-left.svg') no-repeat left center;
background-size: 25px auto;
}
.css-slider .slide:target ~ .slide:hover,
.css-slider .slide:focus ~ .slide:hover {
background-image: url('arrow-left-hover.svg');
}
幻灯片内容
接下来,我们需要控制幻灯片内容到底发生了什么。我设计了这个系统,所以如果你愿意,你可以省略动画部分。这意味着幻灯片将立即切换。下一部分会处理这个问题。
.css-slider .slide .slide-outer {
display: none;
width: 100%;
height: 100%;
}
Slide-inner 纯粹用于处理幻灯片内容的居中。它依赖于显示table 和显示table-cell。
.css-slider .slide .slide-outer .slide-inner {
display: table-cell;
vertical-align: middle;
text-align: center;
width: 100%;
height: 100%;
}
Slide-gfx 实际上只是一个包含您决定放入幻灯片的任何内容的包装器。反射是从此容器生成的,并且还附加了一些其他视觉附加功能。
.css-slider .slide .slide-outer .slide-inner .slide-gfx {
position: relative;
display: inline-block;
z-index: 102;
text-align: left; /* override the centering back to defaults */
}
这部分负责不包含动画时的即时切换。
.css-slider .slide:target .slide-outer,
.css-slider .slide:focus .slide-outer,
.css-slider .slide:last-child .slide-outer {
display: block; /* if they don't support display table */
display: table;
}
last-child 覆盖
由于:last-child 声明会在没有重点的情况下介入,如果您不进行进一步的更改,您会发现某些事情会中断。这是因为:last-child 始终适用,与:focus 不同。为了纠正这个问题,我们需要否定:last-child 的变化,但前提是某些东西已经被关注。这就是下面的 CSS 所做的。
.css-slider .slide:target ~ .slide:last-child,
.css-slider .slide:focus ~ .slide:last-child {
cursor: pointer;
}
.css-slider .slide:target ~ .slide:last-child .slide-outer,
.css-slider .slide:focus ~ .slide:last-child .slide-outer {
display: none;
}
最终恼人的 z-index hack
到目前为止,CSS 已经很笼统了,但总有一些东西......
这部分只需要修复“上一张幻灯片”箭头的可点击性,以便最近的上一帧浮动在其他任何内容之上。如果您不关心上一个滑动操作,那么您可以取消此步骤,只要您隐藏上一个箭头即可。这很烦人,因为如果 CSS 支持 General Sibling Selector 的反转版本,这整个任意部分都可以删除。
基本上以下最多支持5帧,如果需要更多,添加更多。至少好消息是您可以添加比您需要的多得多的帧,而不会产生任何真正的不利影响。显然,如果超过 100 帧,则必须在 CSS 的其余部分中调整其他 z-index。
.css-slider .slide:target ~ .slide:nth-child(1),
.css-slider .slide:focus ~ .slide:nth-child(1) { z-index:99; }
.css-slider .slide:target ~ .slide:nth-child(2),
.css-slider .slide:focus ~ .slide:nth-child(2) { z-index:98; }
.css-slider .slide:target ~ .slide:nth-child(3),
.css-slider .slide:focus ~ .slide:nth-child(3) { z-index:97; }
.css-slider .slide:target ~ .slide:nth-child(4),
.css-slider .slide:focus ~ .slide:nth-child(4) { z-index:96; }
.css-slider .slide:target ~ .slide:nth-child(5),
.css-slider .slide:focus ~ .slide:nth-child(5) { z-index:95; }
动画和附加组件
正如我所说,动画以及所有其余的 CSS (即视觉插件)都是可选的。我将在此处包含其余部分,但细节较少。一旦你了解了上面的技巧和 CSS 过渡或动画,大部分内容都非常简单。像往常一样,它体积庞大的主要原因是供应商前缀;为简洁起见,我已将其删除。要获取完整的 CSS,您显然可以从下面的演示中做到这一点。
请注意:这些插件中的大多数都依赖于非常现代的 CSS,即动画或 SVG
/** --------------------------------------------------------------------------
* HANDLE THE SLIDE ANIMATION (optional)
* ------------------------------------------------------------------------ */
/* Override the default instant slide behaviour */
.css-slider .slide .slide-outer {
display: block !important;
display: table !important;
}
/* set up the transitions */
.css-slider .slide .slide-outer {
transition-property: opacity, transform;
transition-duration: 2s;
transition-timing-function: ease;
}
/* After state */
.css-slider .slide:target ~ .slide .slide-outer,
.css-slider .slide:target ~ .slide:last-child .slide-outer,
.css-slider .slide:focus ~ .slide .slide-outer,
.css-slider .slide:focus ~ .slide:last-child .slide-outer {
transform: translate(-150%,0);
transform: translate3D(-150%,0,0);
}
/* Before state */
.css-slider .slide .slide-outer {
transform: translate(200%,0);
transform: translate3D(200%,0,0);
}
/* Focused state*/
.css-slider .slide:target .slide-outer,
.css-slider .slide:focus .slide-outer,
.css-slider .slide:last-child .slide-outer {
transform: translate(0,0);
transform: translate3D(0,0,0);
}
/** --------------------------------------------------------------------------
* SMALL SCREEN FIX / SLIDE JERK (optional)
* ---------------------------------------------------------------------------
* When we shift 'left' and 'right' values -- in order to allow access to a future
* or past arrow -- this can cause a jump in the responsive scaling of the slide.
* if we transition the left value quickly, it can make this appear less jarring.
*/
.css-slider .slide {
transition-property: left, padding-left;
transition-duration: 1s;
transition-timing-function: ease;
}
/** --------------------------------------------------------------------------
* Add-on module : responsive images
* ------------------------------------------------------------------------ */
.with-responsive-images .slide-gfx img {
width: 100%;
height: auto;
}
/** --------------------------------------------------------------------------
* Add-on module : stop user selection
* ------------------------------------------------------------------------ */
/* if your slides don't need to be selectable, I recommend using this */
.with-selection-disabled {
user-select: none;
}
/** --------------------------------------------------------------------------
* Add-on module : initial fade in
* ------------------------------------------------------------------------ */
.with-fade-in .slide-gfx {
opacity: 0;
}
/* animate into visibility */
.with-fade-in .slide-gfx {
animation: css-slideshow-fade-in 2s;
animation-delay: 1s;
animation-fill-mode: forwards;
}
/* Vebdor animations */
@keyframes css-slideshow-fade-in { from { opacity: 0; } to { opacity: 1; } }
/** --------------------------------------------------------------------------
* Add-on module : slide reflection
* ------------------------------------------------------------------------ */
/* force our slide-gfx to be inline-block and relative positioned */
.with-reflection .slide-gfx {
display: inline-block !important;
}
/* reflection for webkit agents */
.with-reflection .slide-gfx > *:first-child {
-webkit-box-reflect: below 2px
-webkit-gradient(linear, left top, left bottom,
from(transparent), color-stop(0.9, transparent), to(white));
}
/* make sure internal images don't keep inline spacing/margin */
.with-reflection .slide-gfx img {
display: block;
}
/* generate the reflection */
.with-reflection .slide-gfx:after {
content: '';
position: absolute;
display: block;
mask: url("reflection-mask.svg#mask"); /* gradient fade the reflection */
transform: scaleY(-1); /* flip clone to appear as reflection */
opacity: 0.5; /* fade out reflection */
top: 100%;
width: 100%;
height: 60px;
z-index: 200;
margin-top: 2px;
}
/* again, due to element() requiring IDs we need arbitrary code
per each slide and each slide-gfx needs an id */
.with-reflection #s1:after { background: -moz-element(#s1) no-repeat left bottom; }
.with-reflection #s2:after { background: -moz-element(#s2) no-repeat left bottom; }
.with-reflection #s3:after { background: -moz-element(#s3) no-repeat left bottom; }
.with-reflection #s4:after { background: -moz-element(#s4) no-repeat left bottom; }
.with-reflection #s5:after { background: -moz-element(#s5) no-repeat left bottom; }
.with-reflection #s6:after { background: -moz-element(#s6) no-repeat left bottom; }
.with-reflection #s7:after { background: -moz-element(#s7) no-repeat left bottom; }
.with-reflection #s8:after { background: -moz-element(#s8) no-repeat left bottom; }
.with-reflection #s9:after { background: -moz-element(#s9) no-repeat left bottom; }
.with-reflection #s10:after { background: -moz-element(#s10) no-repeat left bottom; }
.with-reflection #s11:after { background: -moz-element(#s11) no-repeat left bottom; }
.with-reflection #s12:after { background: -moz-element(#s12) no-repeat left bottom; }
.with-reflection #s13:after { background: -moz-element(#s13) no-repeat left bottom; }
.with-reflection #s14:after { background: -moz-element(#s14) no-repeat left bottom; }
.with-reflection #s15:after { background: -moz-element(#s15) no-repeat left bottom; }
.with-reflection #s16:after { background: -moz-element(#s16) no-repeat left bottom; }
.with-reflection #s17:after { background: -moz-element(#s17) no-repeat left bottom; }
.with-reflection #s18:after { background: -moz-element(#s18) no-repeat left bottom; }
.with-reflection #s19:after { background: -moz-element(#s19) no-repeat left bottom; }
.with-reflection #s20:after { background: -moz-element(#s20) no-repeat left bottom; }
/** --------------------------------------------------------------------------
* Add-on module : slide zoom (optional, not compatible with slide float)
* ------------------------------------------------------------------------ */
.with-slide-zoom .slide .slide-gfx > *:first-child {
transition-property: max-width;
transition-duration: 2s;
transition-timing-function: ease-in-out;
transition-delay: 0.25s;
}
.with-slide-zoom .slide .slide-gfx > *:first-child:hover {
max-width: 1000px;
}
/** --------------------------------------------------------------------------
* Add-on module : slide float (optional, not compatible with slide zoom)
* ------------------------------------------------------------------------ */
/* inital transition set-up */
.with-slide-float:not(.with-slide-zoom) .slide .slide-gfx > *:first-child,
.with-slide-float-hover:not(.with-slide-zoom) .slide .slide-gfx > *:first-child {
transition-property: transform;
transition-duration: 2s;
transition-timing-function: ease-in-out;
}
/* we need a delay for the non-hover version */
.with-slide-float:not(.with-slide-zoom) .slide .slide-gfx > *:first-child {
transition-delay: 2s;
}
/* initial levitation on focus */
.with-slide-float:not(.with-slide-zoom) .slide:target .slide-gfx > *:first-child,
.with-slide-float:not(.with-slide-zoom) .slide:focus .slide-gfx > *:first-child,
.with-slide-float-hover:not(.with-slide-zoom) .slide .slide-gfx > *:first-child:hover {
transform: translate(0,-40px);
transform: translate3D(0,-40px,0);
}
/* trigger the float animation after 4s */
.with-slide-float:not(.with-slide-zoom) .slide:target .slide-gfx > *:first-child,
.with-slide-float:not(.with-slide-zoom) .slide:focus .slide-gfx > *:first-child,
.with-slide-float-hover:not(.with-slide-zoom) .slide .slide-gfx > *:first-child:hover {
animation: css-slideshow-levitate 4s;
animation-direction: alternate;
animation-fill-iteration-count: infinite;
animation-timing-function: ease-in-out;
animation-delay: 2s;
}
/* longer delay for automatic version i.e. non-hover */
.with-slide-float:not(.with-slide-zoom) .slide:target .slide-gfx > *:first-child,
.with-slide-float:not(.with-slide-zoom) .slide:focus .slide-gfx > *:first-child {
animation-delay: 4s;
}
/* Vebdor animations for the float */
@keyframes css-slideshow-levitate {
from { transform: translate(0,-40px); transform: translate3D(0,-40px,0); }
to { transform: translate(0,-20px); transform: translate3D(0,-20px,0); }
}
/** --------------------------------------------------------------------------
* Add-on module : ground shadow (optional)
* ------------------------------------------------------------------------ */
.with-shadow .slide .slide-gfx:before {
content: '';
background: url('slide-shadow.svg') no-repeat center center;
position: absolute;
bottom: -10px;
left: -20px;
right: -20px;
height: 20px;
z-index: -1;
opacity: 0.7;
}
.with-shadow.with-slide-float .slide .slide-gfx:before,
.with-shadow.with-slide-float-hover .slide .slide-gfx:before {
transition-property: opacity;
transition-duration: 2s;
transition-timing-function: ease-in-out;
}
.with-shadow.with-slide-float .slide .slide-gfx:before {
transition-delay: 2s;
}
.with-shadow.with-slide-float .slide:target .slide-gfx:before,
.with-shadow.with-slide-float .slide:focus .slide-gfx:before,
.with-shadow.with-slide-float .slide:last-child .slide-gfx:before,
.with-shadow.with-slide-float-hover .slide .slide-gfx:hover:before {
opacity: 0.1;
animation: css-slideshow-shadow 4s;
animation-delay: 4s;
animation-direction: alternate;
animation-fill-iteration-count: infinite;
animation-timing-function: ease-in-out;
}
.with-shadow.with-slide-float-hover .slide .slide-gfx:hover:before {
animation-delay: 2s;
}
/* Vebdor animations for the float */
@keyframes css-slideshow-shadow { from { opacity: 0.1; } to { opacity: 0.7; } }
实现示例(v0.2)
http://codelamp.co.uk/css-slideshow/v0.2/
请注意:跳转导航(即圆形点)确实依赖于一小部分 JavaScript。其余的都是纯 CSS。
以前的版本
正如我所说,完善这个系统需要相当长的时间。对于那些可能感兴趣的人,这里是我的(最后一个)版本 0.1——之前有很多;)这采用了稍微不同的方法,涉及视觉和交互式移动部分。最后我放弃了它,因为它涉及更多的浏览器处理,所以更笨重;这个纯色演示没有显示的东西。
http://jsfiddle.net/3cyP8/7/