ホームページ > ウェブフロントエンド > 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 Accessibility Working Group は、開発者が Web パターンやウィジェットにアクセシビリティ セマンティクスを組み込むのを支援するために、Web Accessibility Initiative を開始しました。ウィジェットは、アクセシブルなエクスペリエンスを作成する際に重視されます。マテリアル デザイン、Fluent UI、ヒューマン インターフェイス UI などのデザイン システムは、ブラウザ プラットフォーム上の Web コンポーネントを使用して構築されるウィジェット ベースのデザイン システムであり、ネイティブ プラットフォームに変換される場合は Web アクセシビリティ ガイドラインに厳密に従います。これらのセマンティクスを使用すると、Web サイトのアクセシビリティが向上するだけでなく、開発速度も向上します。

イメージ カルーセルやアラート ダイアログの構築に問題があり、NPM からパッケージをダウンロードする必要があったことがありますか?もうない。 Web アクセシビリティ イニシアチブはあなたをサポートします。 CodePen で表示できるサンプル ウィジェットとパターンが含まれています。サンプルをプロジェクトにダウンロードし、変更すれば完了です。 Image Carousel を構築する方法がわかり、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 Developer Network のドキュメントは次のとおりです:

https://developer.mozilla.org/en-US/docs/Web/API

ブラウザ プラットフォームを使用して構築します。 Web 標準に従って構築します。アクセシブルなエクスペリエンスを構築します。 Web コンポーネントを使用して構築します。フレームワークなしで構築します。

以上がアクセシビリティ セマンティクスをウィジェットに組み込む - Web Accessibility Initiativeの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート