A banner should contain a singular slide or several slides and a call to action, which should contain a title and a lead sentence.
Due to the usability considerations of carousels avoid adding important information or links within the slides that is not available elsewhere on the page, as some users may have difficulty discovering that information or even operating the carousel. Do not add more than 5 slides to the banner, as it is unlikely many users will interact with a carousel at all.
Use on home pages or section pages and provide links that are related to the context of the current section or page.
Do not use on pages that are not home pages or section pages.
General image guidance is available on the image documentation page.
Images are displayed at various sizes dependent on viewing device and orientation. Banner images should always have a 2:1 (width:height) aspect ratio. The required dimension for a banner image is 1200px x 600px. If smaller images are used, they will be stretched and will suffer from degradation in quality, so it is essential to use the correct size of image.
CMS systems which render images to specific sizes (eg. by utilising scripts which specify sizing parameters) should set the dimensions to be 1200px x 600px.
Image specific context parameters are:
A full context example is provided below.
Within the banners
array, each “slide” should be contained within the items
array and include a title
a lead
, an img
object with alt
and src
, and a link
which contains the url
and the link text
.
'banners': [
{
'items': [
{
'title': 'Lorem Ipsum Dolor sit Amet Consectetural',
'lead': 'Lorem ipsum, dolor sit amet consectetur adipisicing elit. Quas repellendus necessitatibus harum quo, nemo magni, dolorem natus atque provident suscipit itaque sit perspiciatis!',
'img': {
'src': '/placeholders/banner/banner-01.jpg',
'alt': 'University campus'
},
'link': {
'text': 'Some call to action',
'url': '/some-cta-link'
}
},
...
]
}
]
{% for banner in banners %}
<section aria-label="Featured" class="uol-banner-outer">
<div class="uol-banner-container {{ 'uol-banner-container--multiple' if banner.items.length > 1 }}">
<{{ 'ol' if banner.items.length > 1 else 'div'}} tabindex="0" class="uol-banner {{ 'uol-banner--multiple' if banner.items.length > 1 }}">
{% for item in banner.items %}
<{{ 'li' if banner.items.length > 1 else 'div'}} class="uol-banner__item">
<h3 class="uol-banner__item__title">{{ item.title }}</h3>
{% if item.img.src %}
<img class="uol-banner__item__img" src="{{ item.img.src }}" alt="{{ item.img.alt }}" loading="lazy">
{% endif %}
{% if item.lead %}
<p class="uol-banner__item__lead">{{ item.lead }}</p>
{% endif %}
{% if item.link %}
<a class="uol-banner__item__link" href="{{ item.link.url }}">{{ item.link.text }}</a>
{% endif %}
</{{ 'li' if banner.items.length > 1 else 'div'}}>
{% endfor %}
</{{ 'ol' if banner.items.length > 1 else 'div'}}>
</div>
</section>
{% endfor %}
<section aria-label="Featured" class="uol-banner-outer">
<div class="uol-banner-container uol-banner-container--multiple">
<ol tabindex="0" class="uol-banner uol-banner--multiple">
<li class="uol-banner__item">
<h3 class="uol-banner__item__title">Lorem Ipsum Dolor sit Amet Consectetural</h3>
<img class="uol-banner__item__img" src="/placeholders/banner/banner-01.jpg" alt="University campus" loading="lazy">
<p class="uol-banner__item__lead">Lorem ipsum, dolor sit amet consectetur adipisicing elit. Quas repellendus necessitatibus harum quo, nemo magni, dolorem natus atque provident suscipit itaque sit perspiciatis!</p>
<a class="uol-banner__item__link" href="/some-cta-link">Some call to action</a>
</li>
<li class="uol-banner__item">
<h3 class="uol-banner__item__title">Nemo voluptatum totam est facere</h3>
<img class="uol-banner__item__img" src="/placeholders/banner/banner-02.jpg" alt="University campus" loading="lazy">
<p class="uol-banner__item__lead">Lorem, ipsum dolor sit amet consectetur adipisicing elit. Corporis, molestiae. Perferendis voluptatem distinctio assumenda magnam.</p>
<a class="uol-banner__item__link" href="/some-cta-link">Some call to action</a>
</li>
<li class="uol-banner__item">
<h3 class="uol-banner__item__title">Ullam laudantium quod tempora dolorum consequuntur provident</h3>
<img class="uol-banner__item__img" src="/placeholders/banner/banner-03.jpg" alt="University campus" loading="lazy">
<p class="uol-banner__item__lead">Lorem ipsum dolor sit amet consectetur adipisicing elit. Expedita enim qui cupiditate aliquam dicta architecto culpa cumque? Commodi facere sequi cumque omnis alias.</p>
<a class="uol-banner__item__link" href="/some-cta-link">Some call to action</a>
</li>
<li class="uol-banner__item">
<h3 class="uol-banner__item__title">Ullam laudantium quod tempora dolorum consequuntur provident</h3>
<img class="uol-banner__item__img" src="/placeholders/banner/banner-04.jpg" alt="University campus" loading="lazy">
<p class="uol-banner__item__lead">Lorem ipsum dolor sit amet consectetur adipisicing elit. Expedita enim qui cupiditate aliquam dicta architecto culpa cumque? Commodi facere sequi cumque omnis alias.</p>
<a class="uol-banner__item__link" href="/some-cta-link">Some call to action</a>
</li>
<li class="uol-banner__item">
<h3 class="uol-banner__item__title">Ullam laudantium quod tempora dolorum consequuntur provident</h3>
<img class="uol-banner__item__img" src="/placeholders/banner/banner-05.jpg" alt="University campus" loading="lazy">
<p class="uol-banner__item__lead">Lorem ipsum dolor sit amet consectetur adipisicing elit. Expedita enim qui cupiditate aliquam dicta architecto culpa cumque? Commodi facere sequi cumque omnis alias.</p>
<a class="uol-banner__item__link" href="/some-cta-link">Some call to action</a>
</li>
</ol>
</div>
</section>
- [ ] Add Aria notice
- [x] Scroll into view on focus
- [x] Handle focus if currently focused button becomes disabled
.uol-banner-outer {
background: $color-black;
overflow: hidden;
}
.uol-banner-container {
box-sizing: border-box;
max-width: $site-container-full;
margin: 0 auto;
position: relative;
color: $color-white;
@include media(">=uol-media-l") {
padding: 0 $spacing-4;
}
}
.uol-banner-container--multiple {
@include media(">=uol-media-l") {
padding-bottom: $spacing-4;
}
}
.uol-banner {
list-style: none;
margin: 0;
padding: 0 0 $spacing-6;
display: flex;
height: auto;
}
.uol-banner--multiple {
@include ds-scrollbars($horizontal: true);
overflow-x: auto;
overflow-y: hidden;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
> * {
flex: 0 0 auto;
}
> * + * {
margin-left: 1rem;
}
@include media(">=uol-media-l") {
max-width: calc(100% - 5rem);
}
}
.uol-banner__item {
position: relative;
display: flex;
flex-direction: column;
box-sizing: border-box;
padding: 0 $spacing-4 $spacing-6;
width: 100%;
transition: opacity 0.2s ease;
@include media(">=uol-media-l") {
width: 100%;
display: block;
padding-bottom: $spacing-4;
// Keep min ratio to avoid crop of absolutely positioned .uol-banner__item__img
&::before {
content: "";
display: block;
width: 0;
height: 0;
padding-bottom: 33%;
float: right;
}
}
.uol-banner--multiple & {
scroll-snap-align: start;
width: 87%;
@include media(">=uol-media-m") {
width: 90%;
}
@include media(">=uol-media-l") {
width: 100%;
display: block;
}
}
}
.uol-banner__item--unfocused {
opacity: 0.5;
}
.uol-banner__item__title {
@extend .uol-typography-heading-2;
margin: $spacing-5 0 $spacing-2;
@include media(">=uol-media-s") {
margin-top: $spacing-6;
}
@include media(">=uol-media-l") {
width: 36%;
margin-top: $spacing-7;
}
@include media(">=uol-media-xl") {
width: 28%;
margin-top: $spacing-8;
}
}
.uol-banner__item__lead {
@extend .uol-typography-paragraph;
margin: 0 0 $spacing-2;
@include media(">=uol-media-l") {
width: 36%;
}
@include media(">=uol-media-xl") {
width: 28%;
}
}
.uol-banner__item__img {
order: -1;
width: calc(100% + #{$spacing-4} * 2);
margin: 0 -#{$spacing-4};
height: auto;
min-height: 1px; // IE11 hack - don't ask why this works
@include media(">=uol-media-l") {
width: 62%;
position: absolute;
top: $spacing-6;
right: 0;
}
@include media(">=uol-media-xl") {
width: 70%;
top: 0;
}
}
.uol-banner__item__link {
display: inline-block;
margin: $spacing-2 0 0;
font-size: 1.125rem;
font-weight: $font-weight-medium--sans-serif;
@include media(">=uol-media-m") {
font-weight: $font-weight-bold--sans-serif;
}
@include media(">=uol-media-l") {
max-width: 36%;
}
@include media(">=uol-media-xl") {
max-width: 28%;
}
&::before {
content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.js & {
text-decoration: none;
&:hover,
&:focus {
text-decoration: underline;
text-decoration-color: $color-brand--bright;
}
}
svg {
position: relative;
margin-top: -0.35em;
top: 0.35em;
left: 0;
margin-left: 0.5em;
fill: $color-brand--bright;
transition: all 0.3s ease 0.2s;
@media (-ms-high-contrast: active) {
fill: windowText;
}
}
&:hover,
&:focus {
svg {
left: 0.4em;
}
}
}
.uol-banner__button {
// Override icon-button specificity
.js .uol-banner-container &.uol-icon--icon-only {
position: absolute;
}
right: calc(13% - #{$spacing-2});
transform: translateX(50%);
transition: all 0.5s ease;
&:disabled {
opacity: 0.7;
}
@include media(">=uol-media-m") {
right: calc(10% - #{$spacing-2});
}
@include media(">=uol-media-l") {
right: 3.125rem;
}
}
.uol-banner__button--prev {
top: $spacing-6;
@include button_focus(-5px, true);
@include media(">=uol-media-xs") {
top: calc(15% - 30px);
}
@include media(">=uol-media-s") {
top: calc(20% - 30px);
}
@include media(">=uol-media-l") {
top: 33%;
transform: translateX(50%) translateY(-50%);
}
}
.uol-banner__button--next {
top: 5.5rem;
@include button_focus(-5px, true);
@include media(">=uol-media-xs") {
top: calc(15% + 30px);
}
@include media(">=uol-media-s") {
top: calc(20% + 30px);
}
@include media(">=uol-media-l") {
top: calc(33% + 4rem);
transform: translateX(50%) translateY(-50%);
}
}
.uol-banner__counter {
position: absolute;
bottom: $spacing-6;
left: $spacing-4;
font-variant-numeric: lining-nums;
@include media(">=uol-media-l") {
left: auto;
bottom: auto;
top: 20%;
right: $spacing-7;
transform: translateX(30%);
padding-bottom: 0.2em;
border-bottom: 1px solid $color-border;
}
}
.uol-banner__counter__current {
color: $color-brand--bright;
}
.uol-banner__counter__total {
&::before {
content: " / ";
}
}
// TODO: Arrows: Should be a global utility
export const bannerArrows = () => {
const svgRightArrow = `<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24" focusable="false" aria-hidden="true">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"/>
</svg>`
const links = document.querySelectorAll('.uol-banner__item__link')
links.forEach( (item) => {
const innerTextArray = item.innerText.trim().split(' ')
// Wrap last word and svg in no-wrap span to avoid wrapping
item.innerHTML = '<span role="text">' + innerTextArray.slice(0, -1).join(' ') + ' <span class="no-wrap">' + innerTextArray[innerTextArray.length - 1] + '' + svgRightArrow + '</span><span>'
})
}
export const bannerCarousel = () => {
const banners = document.querySelectorAll('.uol-banner--multiple')
banners.forEach((banner) => {
const container = banner.closest('.uol-banner-container')
const items = banner.querySelectorAll('.uol-banner__item')
// Create Previous button
const buttonPrev = document.createElement('button')
buttonPrev.type = 'button'
buttonPrev.innerText = 'Select previous banner item'
buttonPrev.classList.add('uol-button')
buttonPrev.classList.add('uol-button--bright')
buttonPrev.classList.add('uol-icon')
buttonPrev.classList.add('uol-icon--icon-only')
buttonPrev.classList.add('uol-icon--mdiArrowLeft')
buttonPrev.classList.add('uol-banner__button')
buttonPrev.classList.add('uol-banner__button--prev')
buttonPrev.disabled = true
// Create Next button
const buttonNext = document.createElement('button')
buttonNext.type = 'button'
buttonNext.innerText = 'Select next banner item'
buttonNext.classList.add('uol-button')
buttonNext.classList.add('uol-button--bright')
buttonNext.classList.add('uol-icon')
buttonNext.classList.add('uol-icon--icon-only')
buttonNext.classList.add('uol-icon--mdiArrowRight')
buttonNext.classList.add('uol-banner__button')
buttonNext.classList.add('uol-banner__button--next')
buttonNext.dataset.galleryModalTarget = 1
// Append both buttons
container.appendChild(buttonPrev)
container.appendChild(buttonNext)
// Append skip link
const skipLink = document.createElement('a')
skipLink.classList.add('uol-skip-link')
skipLink.setAttribute('href', '#main')
skipLink.innerText = 'Skip carousel'
banner.insertAdjacentElement('beforebegin', skipLink)
// Create counter
const counter = document.createElement('span')
counter.classList.add('uol-banner__counter')
counter.setAttribute('role', 'status')
counter.innerHTML = `
<span role="text">
<span class="hide-accessible">Item </span>
<span class="uol-banner__counter__current">1</span>
<span class="hide-accessible"> of </span>
<span class="uol-banner__counter__total">${items.length}</span>
</span>
`
// Append counter
container.appendChild(counter)
// Remove tabindex from scrollable container - not needed when JS enabled
banner.removeAttribute('tabindex')
// Get counter current so we can update it on scroll
const countContainer = container.querySelector('.uol-banner__counter__current')
// Fade out all but first
items.forEach((item) => {
item.classList.add('uol-banner__item--unfocused')
})
items[0].classList.remove('uol-banner__item--unfocused')
let isScrolling = null;
banner.addEventListener('scroll', () => {
let bannerWidth = banner.clientWidth
window.clearTimeout( isScrolling )
isScrolling = setTimeout(() => {
items.forEach((item, itemIndex) => {
let itemLeft = item.getBoundingClientRect().x
if (!itemLeft) // Handle IE11
itemLeft = item.getBoundingClientRect().left
// If item is more than half in view
if (itemLeft >= -10 && itemLeft < (bannerWidth / 2) ) {
// Remove unfocused class
item.classList.remove('uol-banner__item--unfocused')
// Update the current counter
countContainer.innerText = itemIndex + 1
// Update buttons
if (itemIndex == 0) {
buttonNext.disabled = false
if (document.activeElement === buttonPrev) {
buttonNext.focus()
}
buttonPrev.disabled = true
} else if (itemIndex == items.length - 1 ) {
buttonPrev.disabled = false
if (document.activeElement === buttonNext) {
buttonPrev.focus()
}
buttonNext.disabled = true
} else {
buttonPrev.disabled = false
buttonNext.disabled = false
}
buttonPrev.dataset.galleryModalTarget = parseFloat(itemIndex) - 1
buttonNext.dataset.galleryModalTarget = parseFloat(itemIndex) + 1
} else {
// Add unfocused class
item.classList.add('uol-banner__item--unfocused')
}
})
}, 100);
})
// Listen for button clicks
container.querySelectorAll('.uol-banner__button').forEach( (navBtn) => {
navBtn.addEventListener('click', () => {
let targetItem = items[navBtn.dataset.galleryModalTarget]
banner.scrollLeft = targetItem.offsetLeft
})
})
// Scroll to item on link focus
items.forEach( (item) => {
const itemLink = item.querySelector('.uol-banner__item__link')
if (itemLink) {
itemLink.addEventListener('focus', () => {
banner.scrollLeft = item.offsetLeft
})
}
})
})
}
{
"banners": [
{
"items": [
{
"title": "Lorem Ipsum Dolor sit Amet Consectetural",
"lead": "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Quas repellendus necessitatibus harum quo, nemo magni, dolorem natus atque provident suscipit itaque sit perspiciatis!",
"img": {
"src": "/placeholders/banner/banner-01.jpg",
"alt": "University campus"
},
"link": {
"text": "Some call to action",
"url": "/some-cta-link"
}
},
{
"title": "Nemo voluptatum totam est facere",
"lead": "Lorem, ipsum dolor sit amet consectetur adipisicing elit. Corporis, molestiae. Perferendis voluptatem distinctio assumenda magnam.",
"img": {
"src": "/placeholders/banner/banner-02.jpg",
"alt": "University campus"
},
"link": {
"text": "Some call to action",
"url": "/some-cta-link"
}
},
{
"title": "Ullam laudantium quod tempora dolorum consequuntur provident",
"lead": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Expedita enim qui cupiditate aliquam dicta architecto culpa cumque? Commodi facere sequi cumque omnis alias.",
"img": {
"src": "/placeholders/banner/banner-03.jpg",
"alt": "University campus"
},
"link": {
"text": "Some call to action",
"url": "/some-cta-link"
}
},
{
"title": "Ullam laudantium quod tempora dolorum consequuntur provident",
"lead": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Expedita enim qui cupiditate aliquam dicta architecto culpa cumque? Commodi facere sequi cumque omnis alias.",
"img": {
"src": "/placeholders/banner/banner-04.jpg",
"alt": "University campus"
},
"link": {
"text": "Some call to action",
"url": "/some-cta-link"
}
},
{
"title": "Ullam laudantium quod tempora dolorum consequuntur provident",
"lead": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Expedita enim qui cupiditate aliquam dicta architecto culpa cumque? Commodi facere sequi cumque omnis alias.",
"img": {
"src": "/placeholders/banner/banner-05.jpg",
"alt": "University campus"
},
"link": {
"text": "Some call to action",
"url": "/some-cta-link"
}
}
]
}
]
}