W3C 無障礙工作小組啟動了 Web 無障礙計劃,以幫助開發人員將無障礙語義構建到 Web 模式和小部件中。小部件在創造無障礙體驗時受到重視。 Material Design、Fluent UI 和 Human Interface UI 等設計系統是基於 Widget 的設計系統,在瀏覽器平台上使用 Web 元件構建,並且在轉換到本機平台時嚴格遵循 Web 可訪問性指南。使用這些語義不僅可以提高網站的可訪問性,還可以提高您的開發速度。
您在建立影像輪播或警報對話時是否遇到困難,以至於您從 NPM 下載了一個軟體包來完成它?不再。網路輔助功能計畫為您提供支援。他們有範例小部件和模式,您可以使用 CodePen 查看。將範例下載到您的專案中,進行修改,然後就完成了。您將了解如何建立影像輪播並且無需從 NPM 下載軟體包即可存取它
範例影像輪播:
<section> <ul> <li>CSS </li> </ul> <pre class="brush:php;toolbar:false">/* .carousel */ img.reload { padding: 0.25em; display: block-inline; position: relative; top: 6px; height: 0.9em; } .carousel { background-color: #eee; max-width: 900px; } .carousel .carousel-inner { position: relative; } .carousel .carousel-items { padding: 5px; } .carousel .carousel-items.focus { padding: 2px; border: solid 3px #005a9c; } .carousel .carousel-item { display: none; max-height: 400px; max-width: 900px; position: relative; overflow: hidden; width: 100%; } .carousel .carousel-item.active { display: block; } /* More like bootstrap, less accessible */ .carousel .carousel-item .carousel-image a img { height: 100%; width: 100%; } .carousel .carousel-item .carousel-caption a { cursor: pointer; text-decoration: underline; color: #fff; font-weight: 600; } .carousel .carousel-item .carousel-caption a, .carousel .carousel-item .carousel-caption span.contrast { display: inline-block; margin: 0; padding: 6px; background-color: rgb(0 0 0 / 65%); border-radius: 5px; border: 0 solid transparent; } .carousel-moreaccessible .carousel-items .carousel-image a { display: block; margin: 0; padding: 5px; text-decoration: none; border: none; } .carousel-moreaccessible .carousel-item .carousel-caption a { display: inline-block; margin: 0; padding: 6px; color: black; background-color: transparent; border: none; border-radius: 5px; } .carousel-moreaccessible .carousel-item .carousel-caption span.contrast, .carousel-moreaccessible .carousel-item .carousel-caption span.contrast:hover { background-color: transparent; } .carousel .carousel-item .carousel-caption a:hover, .carousel .carousel-item .carousel-caption span.contrast:hover { background-color: rgb(0 0 0 / 100%); } .carousel .carousel-item .carousel-caption a:focus { padding: 4px; border: 2px solid #fff; background-color: rgb(0 0 0 / 100%); outline: none; border-width: 2px solid #fff; color: #fff; } .carousel .carousel-item .carousel-caption p { font-size: 1em; line-height: 1.5; margin-bottom: 0; } .carousel .carousel-item .carousel-caption { position: absolute; right: 15%; bottom: 0; left: 15%; padding-top: 20px; padding-bottom: 20px; color: #fff; text-align: center; } /* Shared CSS for Pause, Previous and Next Buttons */ .carousel .controls { box-sizing: border-box; position: absolute; top: 1em; z-index: 10; display: flex; width: 100%; padding: 0.25em 1.25em 0; } .carousel .controls button { position: absolute; z-index: 10; flex: 0 0 auto; margin: 0; padding: 0; border: none; background: transparent; outline: none; } .carousel .controls button.previous { right: 70px; } .carousel .controls button.next { right: 18px; } /* SVG Controls */ .carousel .controls svg .background { stroke: black; fill: black; stroke-width: 1px; opacity: 0.6; } .carousel .controls svg .border { fill: transparent; stroke: transparent; stroke-width: 2px; } .carousel .controls svg .pause { stroke-width: 4; fill: transparent; stroke: transparent; } .carousel .controls svg .play { stroke-width: 1; fill: transparent; stroke: transparent; } .carousel .controls .pause svg .pause { fill: white; stroke: white; } .carousel .controls .play svg .play { fill: white; stroke: white; } .carousel .controls svg polygon { fill: white; stroke: white; } .carousel .controls button:focus svg .background, .carousel .controls button:hover svg .background, .carousel .controls button:hover svg .border { fill: #005a9c; stroke: #005a9c; opacity: 1; } .carousel .controls button:focus svg .border { stroke: white; } /* More accessible carousel styles, with caption and controls above/below image */ .carousel-moreaccessible { padding: 0; margin: 0; position: relative; border: #eee solid 4px; border-radius: 5px; } /* Shared CSS for Pause and Tab Controls */ .carousel-moreaccessible .controls { position: relative; top: 0; left: 0; padding: 0.25em 0.25em 0; } .carousel.carousel-moreaccessible .controls { position: static; height: 36px; } .carousel.carousel-moreaccessible .controls button.previous { right: 60px; } .carousel.carousel-moreaccessible .controls button.next { right: 6px; } .carousel-moreaccessible .carousel-items, .carousel-moreaccessible .carousel-items.focus { padding: 0; border: none; } .carousel-moreaccessible .carousel-items.focus .carousel-image a { padding: 2px; border: 3px solid #005a9c; } /* More accessible caption styling */ .carousel-moreaccessible .carousel-item { padding: 0; margin: 0; max-height: none; } .carousel-moreaccessible .carousel-item .carousel-caption { position: static; padding: 0; margin: 0; height: 60px; color: black; } .carousel-moreaccessible .carousel-item .carousel-caption p { padding: 0; margin: 0; } .carousel-moreaccessible .carousel-item .carousel-caption h3 { font-size: 1.1em; padding: 0; margin: 0; } .carousel-moreaccessible .carousel-item .carousel-caption a:hover { background-color: rgb(0 0 0 / 20%); } .carousel-moreaccessible .carousel-item .carousel-caption a:focus { padding: 4px; border: 2px solid #005a9c; background-color: transparent; color: black; outline: none; }
/* * File: carousel-prev-next.js * * Desc: Carousel widget with Previous and Next Buttons that implements ARIA Authoring Practices * */ 'use strict'; var CarouselPreviousNext = function (node, options) { // merge passed options with defaults options = Object.assign( { moreaccessible: false, paused: false, norotate: false }, options || {} ); // a prefers-reduced-motion user setting must always override autoplay var hasReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); if (hasReducedMotion.matches) { options.paused = true; } /* DOM properties */ this.domNode = node; this.carouselItemNodes = node.querySelectorAll('.carousel-item'); this.containerNode = node.querySelector('.carousel-items'); this.liveRegionNode = node.querySelector('.carousel-items'); this.pausePlayButtonNode = null; this.previousButtonNode = null; this.nextButtonNode = null; this.playLabel = 'Start automatic slide show'; this.pauseLabel = 'Stop automatic slide show'; /* State properties */ this.hasUserActivatedPlay = false; // set when the user activates the play/pause button this.isAutoRotationDisabled = options.norotate; // This property for disabling auto rotation this.isPlayingEnabled = !options.paused; // This property is also set in updatePlaying method this.timeInterval = 5000; // length of slide rotation in ms this.currentIndex = 0; // index of current slide this.slideTimeout = null; // save reference to setTimeout // Pause Button var elem = document.querySelector('.carousel .controls button.rotation'); if (elem) { this.pausePlayButtonNode = elem; this.pausePlayButtonNode.addEventListener( 'click', this.handlePausePlayButtonClick.bind(this) ); } // Previous Button elem = document.querySelector('.carousel .controls button.previous'); if (elem) { this.previousButtonNode = elem; this.previousButtonNode.addEventListener( 'click', this.handlePreviousButtonClick.bind(this) ); this.previousButtonNode.addEventListener( 'focus', this.handleFocusIn.bind(this) ); this.previousButtonNode.addEventListener( 'blur', this.handleFocusOut.bind(this) ); } // Next Button elem = document.querySelector('.carousel .controls button.next'); if (elem) { this.nextButtonNode = elem; this.nextButtonNode.addEventListener( 'click', this.handleNextButtonClick.bind(this) ); this.nextButtonNode.addEventListener( 'focus', this.handleFocusIn.bind(this) ); this.nextButtonNode.addEventListener( 'blur', this.handleFocusOut.bind(this) ); } // Carousel item events for (var i = 0; i < this.carouselItemNodes.length; i++) { var carouselItemNode = this.carouselItemNodes[i]; // support stopping rotation when any element receives focus in the tabpanel carouselItemNode.addEventListener('focusin', this.handleFocusIn.bind(this)); carouselItemNode.addEventListener( 'focusout', this.handleFocusOut.bind(this) ); var imageLinkNode = carouselItemNode.querySelector('.carousel-image a'); if (imageLinkNode) { imageLinkNode.addEventListener( 'focus', this.handleImageLinkFocus.bind(this) ); imageLinkNode.addEventListener( 'blur', this.handleImageLinkBlur.bind(this) ); } } // Handle hover events this.domNode.addEventListener('mouseover', this.handleMouseOver.bind(this)); this.domNode.addEventListener('mouseout', this.handleMouseOut.bind(this)); // initialize behavior based on options this.enableOrDisableAutoRotation(options.norotate); this.updatePlaying(!options.paused && !options.norotate); this.setAccessibleStyling(options.moreaccessible); this.rotateSlides(); }; /* Public function to disable/enable rotation and if false, hide pause/play button*/ CarouselPreviousNext.prototype.enableOrDisableAutoRotation = function ( disable ) { this.isAutoRotationDisabled = disable; this.pausePlayButtonNode.hidden = disable; }; /* Public function to update controls/caption styling */ CarouselPreviousNext.prototype.setAccessibleStyling = function (accessible) { if (accessible) { this.domNode.classList.add('carousel-moreaccessible'); } else { this.domNode.classList.remove('carousel-moreaccessible'); } }; CarouselPreviousNext.prototype.showCarouselItem = function (index) { this.currentIndex = index; for (var i = 0; i < this.carouselItemNodes.length; i++) { var carouselItemNode = this.carouselItemNodes[i]; if (index === i) { carouselItemNode.classList.add('active'); } else { carouselItemNode.classList.remove('active'); } } }; CarouselPreviousNext.prototype.previousCarouselItem = function () { var nextIndex = this.currentIndex - 1; if (nextIndex < 0) { nextIndex = this.carouselItemNodes.length - 1; } this.showCarouselItem(nextIndex); }; CarouselPreviousNext.prototype.nextCarouselItem = function () { var nextIndex = this.currentIndex + 1; if (nextIndex >= this.carouselItemNodes.length) { nextIndex = 0; } this.showCarouselItem(nextIndex); }; CarouselPreviousNext.prototype.rotateSlides = function () { if (!this.isAutoRotationDisabled) { if ( (!this.hasFocus && !this.hasHover && this.isPlayingEnabled) || this.hasUserActivatedPlay ) { this.nextCarouselItem(); } } this.slideTimeout = setTimeout( this.rotateSlides.bind(this), this.timeInterval ); }; CarouselPreviousNext.prototype.updatePlaying = function (play) { this.isPlayingEnabled = play; if (play) { this.pausePlayButtonNode.setAttribute('aria-label', this.pauseLabel); this.pausePlayButtonNode.classList.remove('play'); this.pausePlayButtonNode.classList.add('pause'); this.liveRegionNode.setAttribute('aria-live', 'off'); } else { this.pausePlayButtonNode.setAttribute('aria-label', this.playLabel); this.pausePlayButtonNode.classList.remove('pause'); this.pausePlayButtonNode.classList.add('play'); this.liveRegionNode.setAttribute('aria-live', 'polite'); } }; /* Event Handlers */ CarouselPreviousNext.prototype.handleImageLinkFocus = function () { this.liveRegionNode.classList.add('focus'); }; CarouselPreviousNext.prototype.handleImageLinkBlur = function () { this.liveRegionNode.classList.remove('focus'); }; CarouselPreviousNext.prototype.handleMouseOver = function (event) { if (!this.pausePlayButtonNode.contains(event.target)) { this.hasHover = true; } }; CarouselPreviousNext.prototype.handleMouseOut = function () { this.hasHover = false; }; /* EVENT HANDLERS */ CarouselPreviousNext.prototype.handlePausePlayButtonClick = function () { this.hasUserActivatedPlay = !this.isPlayingEnabled; this.updatePlaying(!this.isPlayingEnabled); }; CarouselPreviousNext.prototype.handlePreviousButtonClick = function () { this.previousCarouselItem(); }; CarouselPreviousNext.prototype.handleNextButtonClick = function () { this.nextCarouselItem(); }; /* Event Handlers for carousel items*/ CarouselPreviousNext.prototype.handleFocusIn = function () { this.liveRegionNode.setAttribute('aria-live', 'polite'); this.hasFocus = true; }; CarouselPreviousNext.prototype.handleFocusOut = function () { if (this.isPlayingEnabled) { this.liveRegionNode.setAttribute('aria-live', 'off'); } this.hasFocus = false; }; /* Initialize Carousel and options */ window.addEventListener( 'load', function () { var carouselEls = document.querySelectorAll('.carousel'); var carousels = []; // set example behavior based on // default setting of the checkboxes and the parameters in the URL // update checkboxes based on any corresponding URL parameters var checkboxes = document.querySelectorAll( '.carousel-options input[type=checkbox]' ); var urlParams = new URLSearchParams(location.search); var carouselOptions = {}; // initialize example features based on // default setting of the checkboxes and the parameters in the URL // update checkboxes based on any corresponding URL parameters checkboxes.forEach(function (checkbox) { var checked = checkbox.checked; if (urlParams.has(checkbox.value)) { var urlParam = urlParams.get(checkbox.value); if (typeof urlParam === 'string') { checked = urlParam === 'true'; checkbox.checked = checked; } } carouselOptions[checkbox.value] = checkbox.checked; }); carouselEls.forEach(function (node) { carousels.push(new CarouselPreviousNext(node, carouselOptions)); }); // add change event to checkboxes checkboxes.forEach(function (checkbox) { var updateEvent; switch (checkbox.value) { case 'moreaccessible': updateEvent = 'setAccessibleStyling'; break; case 'norotate': updateEvent = 'enableOrDisableAutoRotation'; break; } // update the carousel behavior and URL when a checkbox state changes checkbox.addEventListener('change', function (event) { urlParams.set(event.target.value, event.target.checked + ''); window.history.replaceState( null, '', window.location.pathname + '?' + urlParams ); if (updateEvent) { carousels.forEach(function (carousel) { carousel[updateEvent](event.target.checked); }); } }); }); }, false );
以下是文件連結:
https://www.w3.org/WAI/ARIA/apg/patterns/
https://www.w3.org/WAI/ARIA/apg/practices/
這是 Mozilla 開發者網頁文件:
https://developer.mozilla.org/en-US/docs/Web/API
使用瀏覽器平台建置。使用 Web 標準建置。打造無障礙體驗。使用 Web 元件建置。無需框架即可建置。
以上是將輔助功能語義建置到小部件中 - Web Accessibility Initiative的詳細內容。更多資訊請關注PHP中文網其他相關文章!