Ændringer i pris, variant, lagerstatus og kurv skal formidles til skærmlæsere
Når en kunde vælger en størrelse, og prisen eller lagerstatus ændrer sig, eller når kunden lægger et produkt i kurven, kan seende kunder se opdateringen. Skærmlæserbrugere hører ingenting, så de ved ikke, at produktet er lagt i kurven, eller at den valgte størrelse er udsolgt.
- Regel-id
- vs-live-updates
- Kilde
- Validiscan-kontrol
- Alvorlighed
- Alvorlig
- Rettelsesniveau
- AUTO
- på Shopify, Shopware, WooCommerce og Magento
- Status
- køres
Hvad kontrollen gør
Finder ændringer i pris, variant, lagerstatus og kurv på produkt- og kurvsider, der sker uden et live-område, samt aria-live-områder, der omslutter hele siden (4.1.3).
Kontrollen kører kun på produkt- og kurvsider. Hvert aria-live="polite" eller "assertive" på html, body, main eller et element, der indeholder main, rapporteres.
Den ændrer ét betjeningselement uden for header, navigation, footer og dialoger og blokerer imens afsendelse af formularer. Produktside: det første variant-select (navngivet efter størrelse, farve eller lignende, eller placeret i produktområdet), ellers en gruppe radioknapper til varianter, ellers farveprøveknapper, hvoraf én er valgt. Kurvside: det første antalsfelt, som ændres med én.
Før og efter aflæser den tekster på op til 120 tegn, hvis itemprop, klasse eller id tyder på en pris, lagerstatus, et antal i kurven eller et totalbeløb, samt knappen »Læg i kurv«; siden får op til 2 sekunder til at falde til ro. En ændret synlig tekst rapporteres, medmindre den ligger inde i eller indeholder et live-område (aria-live="polite" eller "assertive", role="status", "alert", "log", output), eller et andet live-område har annonceret en ændring (for priser og lagerstatus ét, der indeholder den nye værdi). En ændring, der ikke går tilbage, når betjeningselementet nulstilles, får resultatet »kræver gennemgang«, som i dag ikke bliver til et fund.
Sådan retter du det
Tilføj et lille, permanent live-område (role="status" eller aria-live="polite") til pris, lagerstatus og antal varer i kurven, og opdater dets tekst, når varianten eller kurven ændrer sig. Sæt ikke aria-live på store containere eller hele siden, for så læser skærmlæsere det hele op igen.
WCAG-succeskriterier
- 4.1.3 Status Messages, niveau AA
Afsnit i EN 301 549
| WCAG-kriterium | Version 3.2.1 | Version 4.1.1 |
|---|---|---|
| 4.1.3 | 9.4.1.3 | 9.4.1.3 |
Hvor en opskrift retter det
Shopify: opskrift live-region-cart-variant
Vis før og efter (1)
sections/main-cart.liquid Ændringer i sections/main-cart.liquid: 1 tilføjet, 1 fjernet
| Linje før | Linje efter | Ændring | Kode |
|---|---|---|---|
| 37 | 37 | ||
| 38 | 38 | <div class="cart__footer"> | |
| 39 | 39 | <h2 class="cart__summary-title">Order summary</h2> | |
| 40 | Fjernet | <p class="totals"> | |
| 40 | Tilføjet | <p class="totals" role="status"> | |
| 41 | 41 | <span class="totals__label">{{ 'sections.cart.subtotal' | t }}</span> | |
| 42 | 42 | <span class="totals__value" data-cart-subtotal>{{ cart.total_price | money_with_currency }}</span> | |
| 43 | 43 | </p> |
sections/main-product.liquid Ændringer i sections/main-product.liquid: 1 tilføjet, 1 fjernet
| Linje før | Linje efter | Ændring | Kode |
|---|---|---|---|
| 71 | 71 | </div> | |
| 72 | 72 | {%- endif %} | |
| 73 | 73 | ||
| 74 | Fjernet | <div class="product__price" data-price-container> | |
| 74 | Tilføjet | <div class="product__price" data-price-container role="status"> | |
| 75 | 75 | {% render 'price', product: product, use_variant: true %} | |
| 76 | 76 | <p class="product__inventory" data-stock>{% if current_variant.available %}{{ 'products.product.in_stock' | t }}{% else %}{{ 'products.product.out_of_stock' | t }}{% endif %}</p> | |
| 77 | 77 | <p class="product__sku">{{ 'products.product.sku' | t }}: <span data-sku>{{ current_variant.sku }}</span></p> |
Shopware: opskrift live-region-cart-variant
Vis før og efter (1)
Resources/views/storefront/page/checkout/cart/index.html.twig Ændringer i Resources/views/storefront/page/checkout/cart/index.html.twig: 2 tilføjet, 2 fjernet
| Linje før | Linje efter | Ændring | Kode |
|---|---|---|---|
| 59 | 59 | <span class="line-item-unit-price-label">{{ 'checkout.cartHeaderUnitPrice'|trans }}:</span> | |
| 60 | 60 | <span class="line-item-unit-price-value">{{ item.unitPrice|currency }}*</span> | |
| 61 | 61 | </div> | |
| 62 | Fjernet | <div class="line-item-total-price"> | |
| 62 | Tilføjet | <div class="line-item-total-price" aria-live="polite" aria-atomic="true"> | |
| 63 | 63 | <span class="line-item-total-price-label">{{ 'checkout.cartHeaderTotalPrice'|trans }}:</span> | |
| 64 | 64 | <span class="line-item-total-price-value" data-line-total>{{ item.totalPrice|currency }}*</span> | |
| 65 | 65 | </div> | |
| 88 | 88 | <div class="col-lg-4 checkout-aside"> | |
| 89 | 89 | <div class="checkout-aside-summary"> | |
| 90 | 90 | <h2 class="checkout-aside-summary-header">{{ 'checkout.summaryHeader'|trans }}</h2> | |
| 91 | Fjernet | <div class="checkout-aside-summary-totals" data-shipping-threshold="{{ shop.shippingThreshold }}" data-shipping-costs="{{ shop.shippingCosts }}"> | |
| 91 | Tilføjet | <div class="checkout-aside-summary-totals" data-shipping-threshold="{{ shop.shippingThreshold }}" data-shipping-costs="{{ shop.shippingCosts }}" aria-live="polite" aria-atomic="true"> | |
| 92 | 92 | <dl class="checkout-aside-summary-list"> | |
| 93 | 93 | <dt class="checkout-aside-summary-label">{{ 'checkout.summaryPositionPrice'|trans }}</dt> | |
| 94 | 94 | <dd class="checkout-aside-summary-value" data-cart-subtotal>{{ cart.subtotal|currency }}*</dd> |
Resources/views/storefront/page/product-detail/buy-widget.html.twig Ændringer i Resources/views/storefront/page/product-detail/buy-widget.html.twig: 1 tilføjet, 1 fjernet
| Linje før | Linje efter | Ændring | Kode |
|---|---|---|---|
| 17 | 17 | {% endblock %} | |
| 18 | 18 | ||
| 19 | 19 | {% block buy_widget_price %} | |
| 20 | Fjernet | <div class="product-detail-price-container"> | |
| 20 | Tilføjet | <div class="product-detail-price-container" aria-live="polite" aria-atomic="true"> | |
| 21 | 21 | <meta itemprop="priceCurrency" content="{{ shop.currency.isoCode }}"> | |
| 22 | 22 | <meta itemprop="price" content="{{ product.price }}"> | |
| 23 | 23 | <p class="product-detail-price{% if product.listPrice %} with-list-price{% endif %}" data-price-display>{{ product.price|currency }}*</p> |
WooCommerce: opskrift live-region-cart-variant
Vis før og efter (2)
assets/js/theme.js Ændringer i assets/js/theme.js: 15 tilføjet, 0 fjernet
| Linje før | Linje efter | Ændring | Kode |
|---|---|---|---|
| 255 | 255 | initCheckout(); | |
| 256 | 256 | initShowPassword(); | |
| 257 | 257 | })(); | |
| 258 | Tilføjet | ||
| 259 | Tilføjet | /* validiscan:live-region-cart-variant */ | |
| 260 | Tilføjet | // Announces cart changes in the status region next to the header cart (WCAG 4.1.3). | |
| 261 | Tilføjet | (function () { | |
| 262 | Tilføjet | const region = document.querySelector('[data-kb-cart-status]'); | |
| 263 | Tilføjet | if (!region || !window.jQuery) return; | |
| 264 | Tilføjet | window.jQuery(document.body).on('added_to_cart removed_from_cart', (event) => { | |
| 265 | Tilføjet | const message = region.getAttribute(event.type === 'added_to_cart' ? 'data-added' : 'data-removed'); | |
| 266 | Tilføjet | region.textContent = ''; | |
| 267 | Tilføjet | window.setTimeout(() => { | |
| 268 | Tilføjet | region.textContent = message || ''; | |
| 269 | Tilføjet | }, 100); | |
| 270 | Tilføjet | }); | |
| 271 | Tilføjet | })(); | |
| 272 | Tilføjet | /* /validiscan:live-region-cart-variant */ |
header.php Ændringer i header.php: 1 tilføjet, 0 fjernet
| Linje før | Linje efter | Ændring | Kode |
|---|---|---|---|
| 67 | 67 | <?php kb_icon( 'bag' ); ?><span class="kb-cart-amount"><?php echo wp_kses_post( WC()->cart->get_cart_subtotal() ); ?></span> | |
| 68 | 68 | <span class="count"><?php echo esc_html( sprintf( _n( '%d item', '%d items', WC()->cart->get_cart_contents_count(), 'storefront' ), WC()->cart->get_cart_contents_count() ) ); ?></span> | |
| 69 | 69 | </a> | |
| 70 | Tilføjet | <span class="screen-reader-text" role="status" data-kb-cart-status data-added="<?php esc_attr_e( 'Product added to your cart.', 'kestrel-birch' ); ?>" data-removed="<?php esc_attr_e( 'Product removed from your cart.', 'kestrel-birch' ); ?>"></span> | |
| 70 | 71 | </li> | |
| 71 | 72 | </ul> | |
| 72 | 73 | </div> |
woocommerce/single-product/add-to-cart/variable.php Ændringer i woocommerce/single-product/add-to-cart/variable.php: 1 tilføjet, 1 fjernet
| Linje før | Linje efter | Ændring | Kode |
|---|---|---|---|
| 65 | 65 | </table> | |
| 66 | 66 | ||
| 67 | 67 | <div class="single_variation_wrap"> | |
| 68 | Fjernet | <div class="woocommerce-variation single_variation"> | |
| 68 | Tilføjet | <div class="woocommerce-variation single_variation" aria-live="polite" aria-atomic="true"> | |
| 69 | 69 | <div class="woocommerce-variation-description"></div> | |
| 70 | 70 | <div class="woocommerce-variation-price"><span class="price"><?php echo wp_kses_post( wc_price( $kb_selected['display_price'] ) ); ?></span></div> | |
| 71 | 71 | <div class="woocommerce-variation-availability"><?php echo wp_kses_post( $kb_selected['availability_html'] ); ?></div> |
Magento: opskrift live-region-cart-variant
Vis før og efter (1)
app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/price/final_price.phtml Ændringer i app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/price/final_price.phtml: 1 tilføjet, 1 fjernet
| Linje før | Linje efter | Ændring | Kode |
|---|---|---|---|
| 13 | 13 | // Fixed variant: the product-page box carries aria-live="polite" aria-atomic="true" and the stock | |
| 14 | 14 | // message (product/view/type/default.phtml) is role="status". | |
| 15 | 15 | ?> | |
| 16 | Fjernet | <div class="price-box price-final_price" data-role="priceBox" data-product-id="<?= (int) $product->getId() ?>" data-price-box="product-id-<?= (int) $product->getId() ?>"<?php if ($isProductPage): ?> data-base-price="<?= (float) $amount ?>"<?php endif; ?>> | |
| 16 | Tilføjet | <div class="price-box price-final_price" data-role="priceBox" data-product-id="<?= (int) $product->getId() ?>" data-price-box="product-id-<?= (int) $product->getId() ?>"<?php if ($isProductPage): ?> data-base-price="<?= (float) $amount ?>"<?php endif; ?> aria-live="polite" aria-atomic="true"> | |
| 17 | 17 | <span class="normal-price"><span class="price-container price-final_price tax weee"><span id="product-price-<?= (int) $product->getId() ?>" data-price-amount="<?= (float) $amount ?>" data-price-type="finalPrice" class="price-wrapper"><span class="price"><?= $escaper->escapeHtml($block->renderAmount($block->getPriceType('final_price')->getAmount(), ['display_label' => false])) ?></span></span></span></span> | |
| 18 | 18 | </div> |
app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/view/type/default.phtml Ændringer i app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/view/type/default.phtml: 1 tilføjet, 1 fjernet
| Linje før | Linje efter | Ændring | Kode |
|---|---|---|---|
| 11 | 11 | ?> | |
| 12 | 12 | <div class="product-info-stock-sku"> | |
| 13 | 13 | <?php if ($block->displayProductStockStatus()): ?> | |
| 14 | Fjernet | <div class="stock available" title="<?= $escaper->escapeHtmlAttr(__('Availability')) ?>"><span><?= $escaper->escapeHtml(__('In stock')) ?></span></div> | |
| 14 | Tilføjet | <div class="stock available" title="<?= $escaper->escapeHtmlAttr(__('Availability')) ?>" role="status"><span><?= $escaper->escapeHtml(__('In stock')) ?></span></div> | |
| 15 | 15 | <?php endif; ?> | |
| 16 | 16 | <div class="product attribute sku"><strong class="type"><?= $escaper->escapeHtml(__('SKU')) ?></strong> <div class="value" itemprop="sku"><?= $escaper->escapeHtml($product->getSku()) ?></div></div> | |
| 17 | 17 | </div> |
Begynd med et gratis tjek af din webshop.
Send din webshops adresse. Validiscan scanner den og svarer med hver fejl, scanningen kan påvise, med siden og koden.
Bestil et gratis tjekEller skriv til info@validiscan.com.
Hvad det gratis tjek omfatter, og hvad det udelader- Du sender
- din webshops adresse
- Sider, der scannes
- op til 15
- Du får
- hver fejl, scanningen kan påvise, med siden og koden
- På din webshop
- kun offentlige sider; intet login, intet købt, ingen formularer sendt
- Hvad det ikke er
- et fuldt audit