Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor carousel #21298

Merged
merged 32 commits into from
Dec 6, 2016
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ef818c0
Start renaming carousel classes
mdo Nov 26, 2016
23664d3
fix nesting and syntax error
mdo Nov 26, 2016
ba329cf
redo css more
mdo Dec 5, 2016
94e2d80
pull in js changes from #18830
mdo Dec 5, 2016
a5c2562
update left/right classes on controls and add img classes
mdo Dec 5, 2016
d57ec90
clear up docs intro
mdo Dec 5, 2016
b0db578
break up example into three separate examples to show flexibility
mdo Dec 5, 2016
6d28f07
redesign indicators
mdo Dec 5, 2016
01f81dd
fix js for previous
mdo Dec 5, 2016
fd87c19
linting
mdo Dec 5, 2016
5abd0ed
move multiple carousels section up, add responsive classes there, ref…
mdo Dec 5, 2016
6782dd6
nuke the text-shadow
mdo Dec 5, 2016
1e3ec89
Merge branch 'v4-dev' into carousel
mdo Dec 5, 2016
1afb695
remove commented out code
mdo Dec 5, 2016
c2c4b5b
remove comment
mdo Dec 5, 2016
8f06eeb
rename and un-nest icons
mdo Dec 5, 2016
5c93cb7
code comment
mdo Dec 5, 2016
8ad30ff
rename in docs
mdo Dec 5, 2016
d157fce
rename control left and right to prev and next; simplify styling by r…
mdo Dec 5, 2016
1abe4c8
redo control icons to use open iconic svgs inlined
mdo Dec 5, 2016
990db24
rip responsive styles; they're unnecessary and likely require overrid…
mdo Dec 5, 2016
875c243
remove unused vars
mdo Dec 5, 2016
410bf38
there's no font, so rip that var
mdo Dec 5, 2016
1980854
rename var
mdo Dec 5, 2016
89f5e65
drop the fixed width of the indicators. instead use the carousel-cont…
mdo Dec 5, 2016
9fca3e3
rename once more
mdo Dec 5, 2016
7c3bda2
simplify svg by only using viewbox
mdo Dec 5, 2016
e40a09b
redo the carousel example to match
mdo Dec 5, 2016
e331db3
linting
mdo Dec 5, 2016
6d9ded8
update migration docs
mdo Dec 5, 2016
4ef547f
drop the .carousel-control base class
mdo Dec 5, 2016
e0edea0
typo
mdo Dec 6, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 86 additions & 38 deletions docs/components/carousel.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ description: A slideshow component for cycling through elements—images or slid
group: components
---

A slideshow component for cycling through elements—images or slides of text—like a carousel. In browsers where the [Page Visibility API](https://www.w3.org/TR/page-visibility/) is supported, the carousel will avoid sliding when the webpage is not visible to the user (such as when the browser tab is inactive, the browser window is minimized, etc.). **Nested carousels are not supported.**
The carousel is a slideshow for cycling through a series of content, built with CSS 3D transforms and a bit of JavaScript. It works with a series of images, text, or custom markup. It also includes support for previous/next controls and indicators.

In browsers where the [Page Visibility API](https://www.w3.org/TR/page-visibility/) is supported, the carousel will avoid sliding when the webpage is not visible to the user (such as when the browser tab is inactive, the browser window is minimized, etc.).

Please be aware that nested carousels are not supported, and carousels are generally not compliant with accessibility standards.

## Contents

Expand All @@ -14,32 +18,86 @@ A slideshow component for cycling through elements—images or slides of text—

## Example

When building carousels, be sure your slides are the same size as one another. The carousel doesn't automatically crop images to the same dimensions for you across slides.
Carousels don't automatically normalize slide dimensions. As such, you may need to use additional utilities or custom styles to appropriately size content. While carousels support previous/next controls and indicators, they're not explicitly required. Add and customize as you see fit.

Be sure to set a unique id on the `.carousel` for optional controls, especially if you're using multiple carousels on a single page.

### Slides only

Here's a carousel with slides only. Note the presence of the `.d-block` and `.img-fluid` on carousel images to prevent browser default image alignment.

{% example html %}
<div id="carouselExampleSlidesOnly" class="carousel slide" data-ride="carousel">
<div class="carousel-inner" role="listbox">
<div class="carousel-item active">
<img class="d-block img-fluid" data-src="holder.js/800x400?auto=yes&bg=777&fg=555&text=First slide" alt="First slide">
</div>
<div class="carousel-item">
<img class="d-block img-fluid" data-src="holder.js/800x400?auto=yes&bg=666&fg=444&text=Second slide" alt="Second slide">
</div>
<div class="carousel-item">
<img class="d-block img-fluid" data-src="holder.js/800x400?auto=yes&bg=555&fg=333&text=Third slide" alt="Third slide">
</div>
</div>
</div>
{% endexample %}

### With controls

Adding in the previous and next controls:

{% example html %}
<div id="carouselExampleControls" class="carousel slide" data-ride="carousel">
<div class="carousel-inner" role="listbox">
<div class="carousel-item active">
<img class="d-block img-fluid" data-src="holder.js/800x400?auto=yes&bg=777&fg=555&text=First slide" alt="First slide">
</div>
<div class="carousel-item">
<img class="d-block img-fluid" data-src="holder.js/800x400?auto=yes&bg=666&fg=444&text=Second slide" alt="Second slide">
</div>
<div class="carousel-item">
<img class="d-block img-fluid" data-src="holder.js/800x400?auto=yes&bg=555&fg=333&text=Third slide" alt="Third slide">
</div>
</div>
<a class="carousel-control carousel-control-prev" href="#carouselExampleControls" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control carousel-control-next" href="#carouselExampleControls" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
{% endexample %}

### With indicators

You can also add the indicators to the carousel, alongside the controls, too.

{% example html %}
<div id="carousel-example-generic" class="carousel slide" data-ride="carousel">
<div id="carouselExampleIndicators" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-target="#carousel-example-generic" data-slide-to="0" class="active"></li>
<li data-target="#carousel-example-generic" data-slide-to="1"></li>
<li data-target="#carousel-example-generic" data-slide-to="2"></li>
<li data-target="#carouselExampleIndicators" data-slide-to="0" class="active"></li>
<li data-target="#carouselExampleIndicators" data-slide-to="1"></li>
<li data-target="#carouselExampleIndicators" data-slide-to="2"></li>
</ol>
<div class="carousel-inner" role="listbox">
<div class="carousel-item active">
<img data-src="holder.js/900x500/auto/#777:#555/text:First slide" alt="First slide">
<img class="d-block img-fluid" data-src="holder.js/800x400?auto=yes&bg=777&fg=555&text=First slide" alt="First slide">
</div>
<div class="carousel-item">
<img data-src="holder.js/900x500/auto/#666:#444/text:Second slide" alt="Second slide">
<img class="d-block img-fluid" data-src="holder.js/800x400?auto=yes&bg=666&fg=444&text=Second slide" alt="Second slide">
</div>
<div class="carousel-item">
<img data-src="holder.js/900x500/auto/#555:#333/text:Third slide" alt="Third slide">
<img class="d-block img-fluid" data-src="holder.js/800x400?auto=yes&bg=555&fg=333&text=Third slide" alt="Third slide">
</div>
</div>
<a class="left carousel-control" href="#carousel-example-generic" role="button" data-slide="prev">
<span class="icon-prev" aria-hidden="true"></span>
<a class="carousel-control carousel-control-prev" href="#carouselExampleIndicators" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#carousel-example-generic" role="button" data-slide="next">
<span class="icon-next" aria-hidden="true"></span>
<a class="carousel-control carousel-control-next" href="#carouselExampleIndicators" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
Expand All @@ -57,45 +115,45 @@ Bootstrap exclusively uses CSS3 for its animations, but Internet Explorer 9 does
The `.active` class needs to be added to one of the slides. Otherwise, the carousel will not be visible.
{% endcallout %}

### Optional captions
### With captions

Add captions to your slides easily with the `.carousel-caption` element within any `.carousel-item`. Place just about any optional HTML within there and it will be automatically aligned and formatted.
Add captions to your slides easily with the `.carousel-caption` element within any `.carousel-item`. They can be easily hidden on smaller viewports, as shown below, with optional [display utilities]({{ site.baseurl }}/utilities/display-property/). We hide them initially with `.d-none` and bring them back on medium-sized devices with `.d-md-block`.

<div class="bd-example">
<div id="carousel-example-captions" class="carousel slide" data-ride="carousel">
<div id="carouselExampleCaptions" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-target="#carousel-example-captions" data-slide-to="0" class="active"></li>
<li data-target="#carousel-example-captions" data-slide-to="1"></li>
<li data-target="#carousel-example-captions" data-slide-to="2"></li>
<li data-target="#carouselExampleCaptions" data-slide-to="0" class="active"></li>
<li data-target="#carouselExampleCaptions" data-slide-to="1"></li>
<li data-target="#carouselExampleCaptions" data-slide-to="2"></li>
</ol>
<div class="carousel-inner" role="listbox">
<div class="carousel-item active">
<img data-src="holder.js/900x500/auto/#777:#777" alt="First slide image">
<div class="carousel-caption">
<img class="d-block img-fluid" data-src="holder.js/800x400?auto=yes&bg=777&fg=555&text=First slide" alt="First slide">
<div class="carousel-caption d-none d-md-block">
<h3>First slide label</h3>
<p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>
</div>
</div>
<div class="carousel-item">
<img data-src="holder.js/900x500/auto/#666:#666" alt="Second slide image">
<div class="carousel-caption">
<img class="d-block img-fluid" data-src="holder.js/800x400?auto=yes&bg=666&fg=444&text=Second slide" alt="Second slide">
<div class="carousel-caption d-none d-md-block">
<h3>Second slide label</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
</div>
<div class="carousel-item">
<img data-src="holder.js/900x500/auto/#555:#555" alt="Third slide image">
<div class="carousel-caption">
<img class="d-block img-fluid" data-src="holder.js/800x400?auto=yes&bg=555&fg=333&text=Third slide" alt="Third slide">
<div class="carousel-caption d-none d-md-block">
<h3>Third slide label</h3>
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur.</p>
</div>
</div>
</div>
<a class="left carousel-control" href="#carousel-example-captions" role="button" data-slide="prev">
<a class="carousel-control carousel-control-left" href="#carouselExampleCaptions" role="button" data-slide="prev">
<span class="icon-prev" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#carousel-example-captions" role="button" data-slide="next">
<a class="carousel-control carousel-control-right" href="#carouselExampleCaptions" role="button" data-slide="next">
<span class="icon-next" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
Expand All @@ -105,25 +163,15 @@ Add captions to your slides easily with the `.carousel-caption` element within a
{% highlight html %}
<div class="carousel-item">
<img src="..." alt="...">
<div class="carousel-caption">
<div class="carousel-caption d-none d-md-block">
<h3>...</h3>
<p>...</p>
</div>
</div>
{% endhighlight %}

{% callout danger %}
#### Accessibility issue

The carousel component is generally not compliant with accessibility standards. If you need to be compliant, please consider other options for presenting your content.
{% endcallout %}

## Usage

### Multiple carousels

Carousels require the use of an `id` on the outermost container (the `.carousel`) for carousel controls to function properly. When adding multiple carousels, or when changing a carousel's `id`, be sure to update the relevant controls.

### Via data attributes

Use data attributes to easily control the position of the carousel. `data-slide` accepts the keywords `prev` or `next`, which alters the slide position relative to its current position. Alternatively, use `data-slide-to` to pass a raw slide index to the carousel `data-slide-to="2"`, which shifts the slide position to a particular index beginning with `0`.
Expand Down
42 changes: 28 additions & 14 deletions js/src/carousel.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ const Carousel = (($) => {

const Direction = {
NEXT : 'next',
PREVIOUS : 'prev'
PREV : 'prev',
LEFT : 'left',
RIGHT : 'right'
}

const Event = {
Expand All @@ -62,16 +64,18 @@ const Carousel = (($) => {
CAROUSEL : 'carousel',
ACTIVE : 'active',
SLIDE : 'slide',
RIGHT : 'right',
LEFT : 'left',
RIGHT : 'carousel-item-right',
LEFT : 'carousel-item-left',
NEXT : 'carousel-item-next',
PREV : 'carousel-item-prev',
ITEM : 'carousel-item'
}

const Selector = {
ACTIVE : '.active',
ACTIVE_ITEM : '.active.carousel-item',
ITEM : '.carousel-item',
NEXT_PREV : '.next, .prev',
NEXT_PREV : '.carousel-item-next, .carousel-item-prev',
INDICATORS : '.carousel-indicators',
DATA_SLIDE : '[data-slide], [data-slide-to]',
DATA_RIDE : '[data-ride="carousel"]'
Expand Down Expand Up @@ -276,10 +280,10 @@ const Carousel = (($) => {
}


_triggerSlideEvent(relatedTarget, directionalClassname) {
_triggerSlideEvent(relatedTarget, eventDirectionName) {
const slideEvent = $.Event(Event.SLIDE, {
relatedTarget,
direction: directionalClassname
direction: eventDirectionName
})

$(this._element).trigger(slideEvent)
Expand Down Expand Up @@ -310,16 +314,26 @@ const Carousel = (($) => {

const isCycling = Boolean(this._interval)

const directionalClassName = direction === Direction.NEXT ?
ClassName.LEFT :
ClassName.RIGHT
let directionalClassName
let orderClassName
let eventDirectionName

if (direction === Direction.NEXT) {
directionalClassName = ClassName.LEFT
orderClassName = ClassName.NEXT
eventDirectionName = Direction.LEFT
} else {
directionalClassName = ClassName.RIGHT
orderClassName = ClassName.PREV
eventDirectionName = Direction.RIGHT
}

if (nextElement && $(nextElement).hasClass(ClassName.ACTIVE)) {
this._isSliding = false
return
}

const slideEvent = this._triggerSlideEvent(nextElement, directionalClassName)
const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName)
if (slideEvent.isDefaultPrevented()) {
return
}
Expand All @@ -339,13 +353,13 @@ const Carousel = (($) => {

const slidEvent = $.Event(Event.SLID, {
relatedTarget: nextElement,
direction: directionalClassName
direction: eventDirectionName
})

if (Util.supportsTransitionEnd() &&
$(this._element).hasClass(ClassName.SLIDE)) {

$(nextElement).addClass(direction)
$(nextElement).addClass(orderClassName)

Util.reflow(nextElement)

Expand All @@ -355,10 +369,10 @@ const Carousel = (($) => {
$(activeElement)
.one(Util.TRANSITION_END, () => {
$(nextElement)
.removeClass(`${directionalClassName} ${direction}`)
.removeClass(`${directionalClassName} ${orderClassName}`)
.addClass(ClassName.ACTIVE)

$(activeElement).removeClass(`${ClassName.ACTIVE} ${direction} ${directionalClassName}`)
$(activeElement).removeClass(`${ClassName.ACTIVE} ${orderClassName} ${directionalClassName}`)

this._isSliding = false

Expand Down
Loading