Bölme düğmesi bileşeni oluşturma

Erişilebilir bir bölünmüş düğme bileşeninin nasıl oluşturulacağına ilişkin temel bir genel bakış.

Bu gönderide, bölme düğmesi oluşturmanın bir yolu üzerine düşüncelerimi paylaşmak istiyorum . Demoyu deneyin.

Demo

Video kullanmayı tercih ederseniz bu gönderinin YouTube versiyonunu kullanabilirsiniz:

Genel Bakış

Bölünmüş düğmeler birer düğmedir birincil düğmeyi ve ek düğmelerin listesini gizleyen reklam öğeleri bulunur. Yararlıdır ikincil dosyayı iç içe yerleştirirken sık kullanılan bir işlemi açığa çıkarmak için (daha az kullanılanlar) işlem gerçekleştiremez. Bölünmüş düğme, yoğun bir tasarım için çok önemli olabilir çok az bile olabilir. Gelişmiş bölme düğmesi, kullanıcının son işlemini bile hatırlayabilir ve birincil sıraya yükseltiyoruz.

Sık kullanılan bir bölme düğmesi e-posta uygulamanızda bulunur. Birincil işlem gönderildi, ancak dilerseniz daha sonra gönderebilir veya taslak kaydedebilirsiniz:

Bir e-posta uygulamasında görülen bölme düğmesi örneği.

Kullanıcının etrafa bakması gerekmediğinden, paylaşılan işlem alanı güzel. Onlar Temel e-posta işlemlerinin bölme düğmesinde olduğunu bilmeniz yeterli.

Parçalar

Bölünmüş düğmenin temel parçalarını ayrıntılarıyla ele almadan önce son kullanıcı deneyimini sağlamak için tasarlanmıştı. VisBug'un erişilebilirliği İnceleme aracı burada, bileşenin makro görünümünü göstermek için kullanılır. her ana bölüm için HTML, stil ve erişilebilirlik özellikleri.

Bölme düğmesini oluşturan HTML öğeleri.

Üst düzey bölünmüş düğme kapsayıcısı

En üst düzey bileşen, Birincil işlemi içeren gui-split-button ve .gui-popup-button.

İncelenen ve bu sınıfta kullanılan CSS özelliklerini gösteren gui-split-button sınıfı.

Birincil işlem düğmesi

Başlangıçta görünür ve odaklanılabilir <button>, kapsayıcının içine iki eşleşen köşe şekli odak, fareyle ve aktif olarak .gui-split-button içinde yer alır.

Düğme öğesi için CSS kurallarını gösteren inceleyici.

Pop-up açma/kapatma düğmesi

"Pop-up düğmesi" destek öğesi, listenin etkin olmasını ve ikincil düğmeler. Bunun bir <button> olmadığına ve odaklanılabilir olmadığına dikkat edin. Ancak, .gui-popup için konumlandırma sabiti ve :focus-within için kullanılan ana makinedir. pop-up'ı gösterir.

gui-popup-button sınıfı için CSS kurallarını gösteren denetleyici.

Pop-up kart

Bu, çapasına kayan kart alt öğesidir .gui-popup-button, konumlandırılmış mutlak ve düğme listesini anlamsal olarak sarmalama.

Sınıf gui-popup&#39;ı için CSS kurallarını gösteren denetleyici

İkincil işlemler

Birincil öğeden biraz daha küçük yazı tipi boyutuna sahip, odaklanılabilir bir <button> işlem düğmesinde bir simge ve ücretsiz bir stilini birincil düğmeye ekleyin.

Düğme öğesi için CSS kurallarını gösteren inceleyici.

Özel özellikler

Aşağıdaki değişkenler renk uyumunu oluşturmaya yardımcı olur ve renk uyumunu oluştururken bileşen genelinde kullanılan değerleri değiştirebilirsiniz.

@custom-media --motionOK (prefers-reduced-motion: no-preference);
@custom-media --dark (prefers-color-scheme: dark);
@custom-media --light (prefers-color-scheme: light);

.gui-split-button {
  --theme:             hsl(220 75% 50%);
  --theme-hover:  hsl(220 75% 45%);
  --theme-active:  hsl(220 75% 40%);
  --theme-text:      hsl(220 75% 25%);
  --theme-border: hsl(220 50% 75%);
  --ontheme:         hsl(220 90% 98%);
  --popupbg:         hsl(220 0% 100%);

  --border: 1px solid var(--theme-border);
  --radius: 6px;
  --in-speed: 50ms;
  --out-speed: 300ms;

  @media (--dark) {
    --theme:             hsl(220 50% 60%);
    --theme-hover:  hsl(220 50% 65%);
    --theme-active:  hsl(220 75% 70%);
    --theme-text:      hsl(220 10% 85%);
    --theme-border: hsl(220 20% 70%);
    --ontheme:         hsl(220 90% 5%);
    --popupbg:         hsl(220 10% 30%);
  }
}

Düzenler ve renk

Brüt kar

Öğe, özel sınıf adına sahip bir <div> ile başlar.

<div class="gui-split-button"></div>

Birincil düğmeyi ve .gui-popup-button öğelerini ekleyin.

<div class="gui-split-button">
  <button>Send</button>
  <span class="gui-popup-button" aria-haspopup="true" aria-expanded="false" title="Open for more actions"></span>
</div>

Aria özelliklerine aria-haspopup ve aria-expanded dikkat edin. Bu işaretler ekran okuyucuların bölme özelliği ve durumunun farkında olması açısından düğme deneyimi. title özelliği herkesin işine yarar.

Bir <svg> simgesi ve .gui-popup kapsayıcı öğesini ekleyin.

<div class="gui-split-button">
  <button>Send</button>
  <span class="gui-popup-button" aria-haspopup="true" aria-expanded="false" title="Open for more actions">
    <svg aria-hidden="true" viewBox="0 0 20 20">
      <path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" />
    </svg>
    <ul class="gui-popup"></ul>
  </span>
</div>

Basit pop-up yerleşimi için .gui-popup, düğmenin alt öğesidir. tarafından genişletilir. Bu stratejinin yakaladığı tek sorun .gui-split-button kapsayıcı overflow: hidden etiketini kullanamaz, çünkü pop-up'ın yardımcı olur.

<li><button> içerikle doldurulmuş bir <ul> kendini "düğme olarak" duyurur liste" Örneğin, ekran okuyucularla tam olarak sunulan arayüz.

<div class="gui-split-button">
  <button>Send</button>
  <span class="gui-popup-button" aria-haspopup="true" aria-expanded="false" title="Open for more actions">
    <svg aria-hidden="true" viewBox="0 0 20 20">
      <path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" />
    </svg>
    <ul class="gui-popup">
      <li>
        <button>Schedule for later</button>
      </li>
      <li>
        <button>Delete</button>
      </li>
      <li>
        <button>Save draft</button>
      </li>
    </ul>
  </span>
</div>

Zevk kazanmak ve renklerle eğlenmek için ikincil düğmelere simgeler ekledim https://heroicons.com adresinde bulabilirsiniz. Her ikisi için simgeler isteğe bağlıdır birincil ve ikincil düğmeleri tıklayın.

<div class="gui-split-button">
  <button>Send</button>
  <span class="gui-popup-button" aria-haspopup="true" aria-expanded="false" title="Open for more actions">
    <svg aria-hidden="true" viewBox="0 0 20 20">
      <path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" />
    </svg>
    <ul class="gui-popup">
      <li><button>
        <svg aria-hidden="true" viewBox="0 0 24 24">
          <path d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
        </svg>
        Schedule for later
      </button></li>
      <li><button>
        <svg aria-hidden="true" viewBox="0 0 24 24">
          <path d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
        </svg>
        Delete
      </button></li>
      <li><button>
        <svg aria-hidden="true" viewBox="0 0 24 24">
          <path d="M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z" />
        </svg>
        Save draft
      </button></li>
    </ul>
  </span>
</div>

Stiller

HTML ve içerik yerine, stiller renk ve düzen sağlamaya hazır olur.

Bölünmüş düğme kapsayıcısının stilini belirleme

inline-flex görüntülü reklam türü, bu sarmalama bileşeni için diğer bölme düğmeleri, işlemleri veya öğeleri ile satır içine sığmalıdır.

.gui-split-button {
  display: inline-flex;
  border-radius: var(--radius);
  background: var(--theme);
  color: var(--ontheme);
  fill: var(--ontheme);

  touch-action: manipulation;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

Bölme düğmesi.

<button> stili

Düğmeler ne kadar kod gerektiğini gizleme konusunda çok başarılıdır. Şunları yapmanız gerekebilir: varsayılan stillerini geri alabilir veya değiştirebilir, ancak aynı zamanda bazı devralma, etkileşim durumları ekleme, çeşitli kullanıcı tercihlerine ve giriş türleri. Düğme stilleri hızlıca eklenir.

Bu düğmeler, arka planı ortak oldukları için normal düğmelerden farklıdır üst öğe içerir. Genellikle bir düğmenin arka planı ve metin rengi kendine ait olur. Fakat bunlar bunu paylaşır ve yalnızca etkileşimle ilgili kendi geçmişlerini uygular.

.gui-split-button button {
  cursor: pointer;
  appearance: none;
  background: none;
  border: none;

  display: inline-flex;
  align-items: center;
  gap: 1ch;
  white-space: nowrap;

  font-family: inherit;
  font-size: inherit;
  font-weight: 500;

  padding-block: 1.25ch;
  padding-inline: 2.5ch;

  color: var(--ontheme);
  outline-color: var(--theme);
  outline-offset: -5px;
}

Birkaç CSS içeren etkileşim durumları ekleyin sözde sınıflar ve eşleştirme kullanımı eyalete ilişkin özel özellikler:

.gui-split-button button {
  

  &:is(:hover, :focus-visible) {
    background: var(--theme-hover);
    color: var(--ontheme);

    & > svg {
      stroke: currentColor;
      fill: none;
    }
  }

  &:active {
    background: var(--theme-active);
  }
}

Birincil düğmenin tasarım efektini tamamlaması için birkaç özel stile ihtiyacı vardır:

.gui-split-button > button {
  border-end-start-radius: var(--radius);
  border-start-start-radius: var(--radius);

  & > svg {
    fill: none;
    stroke: var(--ontheme);
  }
}

Son olarak, biraz daha şık olması için açık tema düğmesi ve simgesi gölge:

.gui-split-button {
  @media (--light) {
    & > button,
    & button:is(:focus-visible, :hover) {
      text-shadow: 0 1px 0 var(--theme-active);
    }
    & > .gui-popup-button > svg,
    & button:is(:focus-visible, :hover) > svg {
      filter: drop-shadow(0 1px 0 var(--theme-active));
    }
  }
}

İyi bir düğme, mikro etkileşimlere ve çok küçük ayrıntılara dikkat çekmiş.

:focus-visible ile ilgili bir not

Düğme stillerinin :focus yerine :focus-visible özelliğini nasıl kullandığına dikkat edin. :focus. erişilebilir bir kullanıcı arayüzü oluşturmak için çok önemli bir dezavantaj: kullanıcının reklamı görmesinin gerekip gerekmediği her odak için geçerlidir.

Aşağıdaki video, bu mikro etkileşimi kırmaya ve böylece :focus-visible akıllı bir alternatiftir.

Pop-up düğmesinin stilini belirleme

Bir simgeyi ortalamak ve pop-up düğme listesini sabitlemek için kullanılan 4ch flex kutusu. Beğenme birincil düğme, üzerine gelinceye veya etkileşimde bulunulana kadar şeffaf ve dolduracak şekilde esnetilmişti.

Pop-up&#39;ı tetiklemek için kullanılan bölme düğmesinin ok kısmı.

.gui-popup-button {
  inline-size: 4ch;
  cursor: pointer;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-inline-start: var(--border);
  border-start-end-radius: var(--radius);
  border-end-end-radius: var(--radius);
}

CSS ile fareyle üzerine gelin, odak ve etkin durumlarda katman oluşturun İç içe yerleştirme ve :is() işlevsel seçici:

.gui-popup-button {
  

  &:is(:hover,:focus-within) {
    background: var(--theme-hover);
  }

  /* fixes iOS trying to be helpful */
  &:focus {
    outline: none;
  }

  &:active {
    background: var(--theme-active);
  }
}

Bu stiller, pop-up'ın gösterilmesi ve gizlenmesi için en önemli unsurdur. .gui-popup-button, alt öğelerinden herhangi birinde focus konumuna sahip (opacity olarak ayarlanmış) ve pointer-events, simge ve pop-up'ta gösterilir.

.gui-popup-button {
  

  &:focus-within {
    & > svg {
      transition-duration: var(--in-speed);
      transform: rotateZ(.5turn);
    }
    & > .gui-popup {
      transition-duration: var(--in-speed);
      opacity: 1;
      transform: translateY(0);
      pointer-events: auto;
    }
  }
}

Giriş ve çıkış stilleri tamamlandığında, son parça koşullu olarak kullanıcının hareket tercihine bağlı olarak değiştirilir:

.gui-popup-button {
  

  @media (--motionOK) {
    & > svg {
      transition: transform var(--out-speed) ease;
    }
    & > .gui-popup {
      transform: translateY(5px);

      transition:
        opacity var(--out-speed) ease,
        transform var(--out-speed) ease;
    }
  }
}

Koda dikkat edildiğinde kullanıcılar için opaklık geçişinin hâlâ devam ettiğini fark edebilirsiniz daha az hareket etmeyi tercih eder.

Pop-up'ın stilini belirleme

.gui-popup öğesi, özel özellikler kullanan bir kayan kart düğmesi listesidir ve göreceli birimlerin daha küçük, etkileşimli olarak birincil öğe ile eşleştirilmesi düğmesini ve renk kullanımıyla ilgili markayı dikkate alın. Simgelerin kontrastının daha az olduğuna dikkat edin. daha ince ve gölgenin de göze hitap eden mavi bir tonu var. Düğmelerde olduğu gibi güçlü bir kullanıcı arayüzü ve kullanıcı deneyimi sunmak, bu küçük ayrıntıların bir araya gelmesinden kaynaklanır.

Kayan kart öğesi.

.gui-popup {
  --shadow: 220 70% 15%;
  --shadow-strength: 1%;

  opacity: 0;
  pointer-events: none;

  position: absolute;
  bottom: 80%;
  left: -1.5ch;

  list-style-type: none;
  background: var(--popupbg);
  color: var(--theme-text);
  padding-inline: 0;
  padding-block: .5ch;
  border-radius: var(--radius);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  font-size: .9em;
  transition: opacity var(--out-speed) ease;

  box-shadow:
    0 -2px 5px 0 hsl(var(--shadow) / calc(var(--shadow-strength) + 5%)),
    0 1px 1px -2px hsl(var(--shadow) / calc(var(--shadow-strength) + 10%)),
    0 2px 2px -2px hsl(var(--shadow) / calc(var(--shadow-strength) + 12%)),
    0 5px 5px -2px hsl(var(--shadow) / calc(var(--shadow-strength) + 13%)),
    0 9px 9px -2px hsl(var(--shadow) / calc(var(--shadow-strength) + 14%)),
    0 16px 16px -2px hsl(var(--shadow) / calc(var(--shadow-strength) + 20%))
  ;
}

Simgelere ve düğmelere, her koyu temada güzel bir stil vermek için marka renkleri verilmiştir ve ışık temalı kart:

Ödeme, Hızlı Ödeme ve Daha sonrası için kaydet özellikleri için bağlantılar ve simgeler.

.gui-popup {
  

  & svg {
    fill: var(--popupbg);
    stroke: var(--theme);

    @media (prefers-color-scheme: dark) {
      stroke: var(--theme-border);
    }
  }

  & button {
    color: var(--theme-text);
    width: 100%;
  }
}

Koyu tema pop-up'ında metin ve simge gölgesi eklemelerinin yanı sıra biraz daha fazla yoğun kutu gölgesi:

Koyu temadaki pop-up.

.gui-popup {
  

  @media (--dark) {
    --shadow-strength: 5%;
    --shadow: 220 3% 2%;

    & button:not(:focus-visible, :hover) {
      text-shadow: 0 1px 0 var(--ontheme);
    }

    & button:not(:focus-visible, :hover) > svg {
      filter: drop-shadow(0 1px 0 var(--ontheme));
    }
  }
}

Genel <svg> simgesi stilleri

Tüm simgeler, Google tarafından kullanılan düğmeye font-size göre büyüktür. olarak ch birimini inline-size. Simgelerin yumuşak ve sade olması için her birine gerekir.

.gui-split-button svg {
  inline-size: 2ch;
  box-sizing: content-box;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 2px;
}

Sağdan sola düzen

Tüm karmaşık işleri mantıksal özellikler yapar. Kullanılan mantıksal özelliklerin listesi aşağıda verilmiştir: - display: inline-flex satır içi esnek öğe oluşturur. - padding yerine padding-block ve padding-inline mantıksal kenarları doldurmanın avantajlarından yararlanın. - border-end-start-radius ve arkadaşlarınız köşeleri belgenin yönüne göre yuvarlatın. - width yerine inline-size, boyutun fiziksel boyutlara bağlı kalmamasını sağlar. - border-inline-start, başlangıca bir kenarlık ekler. Bu kenarlık komut dosyası yönüne bağlı olarak sağda veya solda olabilir.

JavaScript

Aşağıdaki JavaScript'lerin neredeyse tümü erişilebilirliği artırmak içindir. Bunlardan ikisi görevleri biraz kolaylaştırmak için yardımcı kitaplıklar kullanılır. BlingBlingJS, kısa ve öz ifadeler için kullanılır. DOM sorguları ve kolay etkinlik işleyici kurulumu roving-ux, erişimi kolaylaştırır. klavye ve oyun kumandası etkileşimlerini takip eder.

import $ from 'blingblingjs'
import {rovingIndex} from 'roving-ux'

const splitButtons = $('.gui-split-button')
const popupButtons = $('.gui-popup-button')

Yukarıdaki kitaplıklar içe aktarıldıktan ve öğeler seçilip değişkenlerini kullanarak, deneyimi yükseltmek işlevin tamamlanmasına birkaç adım uzanıyor.

Dönme indeksi

Bir klavye veya ekran okuyucu .gui-popup-button cihazına odaklandığında odağı alan adındaki ilk (veya en son odaklanılan) düğmeye .gui-popup. Kitaplık, element ve target ile bunu yapmamıza yardımcı olur parametreleridir.

popupButtons.forEach(element =>
  rovingIndex({
    element,
    target: 'button',
  }))

Öğe artık odağı hedef <button> alt öğesine iletir ve seçeneklere göz atmak için standart ok tuşuyla gezinme.

aria-expanded değiştiriliyor

Bir pop-up'ın gösterilip saklandığı görsel olarak açıkça görülse de ekran okuyucuların görsel ipuçlarından daha fazlasına ihtiyacı vardır. Ekran okuyucuya uygun bir özelliği açıp kapatarak burada CSS'ye dayalı :focus-within etkileşimini tamamlamak için JavaScript kullanılır.

popupButtons.on('focusin', e => {
  e.currentTarget.setAttribute('aria-expanded', true)
})

popupButtons.on('focusout', e => {
  e.currentTarget.setAttribute('aria-expanded', false)
})

Escape anahtarını etkinleştirme

Kullanıcının odağı kasıtlı olarak bir tuzağa düşürüldü. Bu da onu bir çıkış yolu sağlar. En yaygın yöntem, Escape anahtarının kullanılmasına izin vermektir. Bunu yapmak için pop-up düğmesine basıldığından emin olun, çünkü klavyedeki herhangi bir etkinlik bu ebeveyne yükselir.

popupButtons.on('keyup', e => {
  if (e.code === 'Escape')
    e.target.blur()
})

Pop-up düğmesi Escape tuşuna basıldığını görürse odağı kendisinden kaldırır şununla: blur()

Böl düğmesi tıklamaları

Son olarak, kullanıcı düğmeleri tıklarsa, dokunursa veya klavyeyle etkileşimde bulunursa uygun işlemi gerçekleştirmesi gerekir. Etkinlik baloncuğu kullanılıyor burada tekrar ediyorum, ancak bu sefer .gui-split-button kapsayıcısında çocuk pop-up'ından veya birincil işlemden gelen tıklama sayısı.

splitButtons.on('click', event => {
  if (event.target.nodeName !== 'BUTTON') return
  console.info(event.target.innerText)
})

Sonuç

Şimdi bunu nasıl yaptığımı öğrendiğinize göre siz nasıl ‽ 🙂

Gelin, yaklaşımlarımızı çeşitlendirelim ve web'de içerik geliştirmenin tüm yollarını öğrenelim. Bir demo oluşturup beni tweet'le bağlantıları eklerim aşağıdaki topluluk remiksleri bölümüne gidin!

Topluluk remiksleri