首頁 > web前端 > css教學 > 將輔助功能語義建置到小部件中 - Web Accessibility Initiative

將輔助功能語義建置到小部件中 - Web Accessibility Initiative

Susan Sarandon
發布: 2024-12-30 14:01:12
原創
473 人瀏覽過

Build Accessibility Semantics into Widgets - Web Accessibility Initiative

W3C 無障礙工作小組啟動了 Web 無障礙計劃,以幫助開發人員將無障礙語義構建到 Web 模式和小部件中。小部件在創造無障礙體驗時受到重視。 Material Design、Fluent UI 和 Human Interface UI 等設計系統是基於 Widget 的設計系統,在瀏覽器平台上使用 Web 元件構建,並且在轉換到本機平台時嚴格遵循 Web 可訪問性指南。使用這些語義不僅可以提高網站的可訪問性,還可以提高您的開發速度。

您在建立影像輪播或警報對話時是否遇到困難,以至於您從 NPM 下載了一個軟體包來完成它?不再。網路輔助功能計畫為您提供支援。他們有範例小部件和模式,您可以使用 CodePen 查看。將範例下載到您的專案中,進行修改,然後就完成了。您將了解如何建立影像輪播並且無需從 NPM 下載軟體包即可存取它

範例影像輪播:

  • HTML
<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;
}
登入後複製
  • JS
/*
 *   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中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板