Peb*_*bbl 16 css slideshow carousel
一段时间以来,我一直在努力实现一个仅限CSS的幻灯片,一个会:
我遇到的大多数其他CSS幻灯片都没有勾选所有这些框.
值得庆幸的是,我花了这么长时间以来,浏览器本身已经改进了无端,现在实际上已经非常广泛,尽管有一些"现代"的CSS主义.为了防止其他人对我有用,我想我会在这里发布.
那么如何使用CSS和以下标记创建可导航的幻灯片?
<ul class="css-slider">
<li class="slide"><img src="photos/a.jpg" /></li>
<li class="slide"><img src="photos/b.jpg" /></li>
<li class="slide"><img src="photos/c.jpg" /></li>
<li class="slide"><img src="photos/d.jpg" /></li>
<li class="slide"><img src="photos/e.jpg" /></li>
</ul>
Run Code Online (Sandbox Code Playgroud)
Peb*_*bbl 48
UPDATE: There seems to be a bug with Firefox 32 (Mac) that means ellipses will not render in SVG masks, this leads to the reflection failing... and don't get me started on what Chrome 37.0.2062.120 (Mac) is doing if you hover off any of the images in the implemented example at the foot of this answer.
— 18 Sept 2014.
The slides are built up out of two main parts, a visual part and an interactive part. The interactive part pretty much stays static, and the visual part is animated. After much playing around I extended the initial HTML structure (see above) to incorporate a few extra wrappers around the slide's content. This allows for the separate interactive and visual parts, and also extra flexibility for other useful abilities i.e. like vertical centering and reflections.
<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>
Run Code Online (Sandbox Code Playgroud)
Now in order to actually have any system behave as a slideshow, you need to have some way to identify the current or focused slide. In this case i’m relying on :focus
to handle this distinction. You might have noticed the addition of tabindex=“1”
above, this is so that the pseudo-class :focus
is applied to unexpected elements like <li>
— this was required mainly for webkit-based browsers, but may help out other agents too.
So put simply, all the slides are stacked one on top of the other, the current focused slide is centred to the viewport and given the highest z-index
, the slide before the focused slide is translated off screen to the left, and the slide after the focused slide is translated off screen to the right. It should be noted that the xy translations only effect the visual content of the slides, the interactive parts are still layered atop one another filling the entire viewport area, well almost...
I say almost because in order for the focus to be triggered on the next and previous slides — via mouse or touch — part of their interactive layers must be accessible and clickable by the user. Using a mixture of left
, right
and padding
the correct areas can be revealed without displacing the visual elements.
So, as the current focused slide changes, so do the areas of the interactive layers that are accessible. Each time a user clicks the next or previous arrows, they are actually focusing on the adjacent <li>
element, rather than clicking a link that performs any kind of action.
In order to get this to work on Webkit browsers the tabindex
attribute needs to be used so that the :focus
Pseudo-class will function on the whatever base element you use to represent a slide.
Because of the tricks employed, the slides will play in a reversed-dom-order.
You can navigate the slideshow using tab, however, it will navigate backwards, due to point 2. If you have a Mac, you may need to tweak your os settings before tab will function.
Due to the left
, right
trick to expose the navigation arrows, there is a slight visual glitch when navigating forwards — in that you can see the subsequent previous arrow quickly animate into place.
Because this system works based on :focus
whenever focus is lost the slideshow reverts back to the initial slide, for this reason, sub links will not work within your slides — unless you enhance interactions with JavaScript.
My demo makes use of SVG background images, these are obviously optional and do not work on older browsers.
IE7和IE8甚至无法理解
:last-child
或者:nth-child
所以没有,但它不为他们工作.
在下面的演示中,您将看到有一些JavaScript蓬勃发展,这些可以帮助展示构造可以做什么,或者它们逐步增强.复选框仅适用于演示,应允许您启用或禁用某些功能.这些功能由简单的类应用:
please note: the reflection add-on relies on arbitrary markup attributes. You will have to add unique ids to each .slide, and then extend the CSS to take them into account.
Ok, so to start with here is the basic set-up. First off, because my slideshow is with images I've set some basic image styling, this is all optional.
.slide-gfx img {
max-width: 600px;
max-height: auto;
border-radius: 20px;
box-shadow: 0 0 80px rgba(255,255,255,1);
}
Run Code Online (Sandbox Code Playgroud)
The slider mask was added as a wrapper to the entire slideshow, to prevent the window scrollbars from displaying when operating the slideshow at full screen size. This again is optional.
.css-slider-mask {
display: block;
overflow: hidden;
width: 100%;
height: 100%;
}
Run Code Online (Sandbox Code Playgroud)
Now we get the actual set-up that is required for the slider. This first part is quite straight-forward, save for the display: none;
part. This initially hides the slideshow from everyone, but is then later overridden for browsers that support :nth-child
. It is most likely that your <body>
element will be the 2nd child, but you should check before using this.
.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;
}
Run Code Online (Sandbox Code Playgroud)
Next we get down to slide specifics. Because of the non-existence of a reversed General Sibling Selector (~
), all default styles for slides represent the future (or next) state. This is because there isn't an actual way to select the future slides.
.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! */
}
Run Code Online (Sandbox Code Playgroud)
Again, by default we style the forward arrow, and then override later for the current and past slides.
.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;
}
Run Code Online (Sandbox Code Playgroud)
Now the focused slide, the key items here are :focus
(as I've already explained) and :last-child
which I haven't. Last Child is used rather than First Child because, again, we have to work backwards (all due to the lack of a reverse General Sibling Selector ~
). Why either child is needed at all is so that we can "focus" an initial slide when there is no current focus i.e. on page load.
.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;
}
Run Code Online (Sandbox Code Playgroud)
Now we need to affect all the slides that slip into the past. I have a avoided mentioning the :target
pseudo-class prior to now, basically this has been implemented to support the "jump nav". There are two reasons why I wont sing the praises of the the "jump nav":
Anyway, the trick to selecting slides that are in the past, hinges on the General Sibling Selector. The following construct basically means select .slide(s) that you find after the .slide that has :focus.
.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');
}
Run Code Online (Sandbox Code Playgroud)
Next up we need to control what exactly happens with our slide contents. I have designed this system so that if you want to, you can leave out the animation section. This will mean that the slides will switch instantaneously. This next part takes care of that.
.css-slider .slide .slide-outer {
display: none;
width: 100%;
height: 100%;
}
Run Code Online (Sandbox Code Playgroud)
Slide-inner is purely used to handle the centering of the slide contents. It relies on display table
and display table-cell
.
.css-slider .slide .slide-outer .slide-inner {
display: table-cell;
vertical-align: middle;
text-align: center;
width: 100%;
height: 100%;
}
Run Code Online (Sandbox Code Playgroud)
Slide-gfx is literally just a containing wrapper for whatever you decide to put in your slideshow. The reflection is generated from this container, and a few other visual extras are attached to it also.
.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 */
}
Run Code Online (Sandbox Code Playgroud)
This part is responsible for the instant switch when no animation is included.
.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;
}
Run Code Online (Sandbox Code Playgroud)
Due to the :last-child
declarations that step in when nothing is focused, if you were to make no further changes, you would find certain things break. This is because :last-child
always applies, unlike :focus
. To rectify this we need to negate the :last-child
changes, but only when something has been focused. That's what the following CSS does.
.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;
}
Run Code Online (Sandbox Code Playgroud)
So far the CSS has been quite generalised, but there is always something...
This part is only required to fix the click-ability of the 'previous slide' arrow, so that the most recent previous frame floats above anything else. If you don't care about a previous slide action then you could do away with this step, as long as you hide the previous arrow. It's rather annoying because this whole arbitrary section could be done away with if CSS supported an inverted version of the General Sibling Selector.
Basically the following will support up to 5 frames, if you need more, add more. The good news at least is you can add far more frames than you need without any real adverse effects. Obviously if you go above 100 frames you'll have to adjust other z-indexes in the rest of the CSS.
.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; }
Run Code Online (Sandbox Code Playgroud)
As I have stated, the animation is optional, along with all the rest of the CSS i.e. visual add-ons. I'll include the rest here with less detail. Most of it is quite straight-forward once you know the tricks above and CSS transitions or animations. The main reason for it's bulk, is, as usual, vendor-prefixes; which I've removed for brevity. To source the full CSS you can obviously do so from the demo below.
please note: Most of these add-ons rely on quite modern CSS i.e. animations or SVGs
/** --------------------------------------------------------------------------
* 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; } }
Run Code Online (Sandbox Code Playgroud)
http://codelamp.co.uk/css-slideshow/v0.2/
please note: the jump nav i.e. circular dots do rely on a small bit of JavaScript. The rest is pure CSS.
正如我所说,改进这个系统需要相当多的时间.对于那些可能感兴趣的人,这里是我的(最后)版本0.1 - 以前有过很多;)这采用了略有不同的方法,涉及视觉和交互式移动部件.最后我废弃它,因为它涉及更多的浏览器处理,因此更加笨重; 这个纯色演示没有透露的东西.