یک نمای کلی از نحوه ایجاد یک نوار بارگیری سازگار با رنگ و در دسترس با عنصر <progress>
.
در این پست میخواهم در مورد چگونگی ساخت یک نوار بارگیری سازگار و قابل دسترس با عنصر <progress>
فکر کنم. نسخه ی نمایشی را امتحان کنید و منبع را مشاهده کنید !
اگر ویدیو را ترجیح می دهید، در اینجا یک نسخه YouTube از این پست وجود دارد:
نمای کلی
عنصر <progress>
بازخورد بصری و شنیداری را در مورد تکمیل به کاربران ارائه می دهد. این بازخورد بصری برای سناریوهایی مانند: پیشرفت از طریق فرم، نمایش اطلاعات بارگیری یا آپلود، یا حتی نشان دادن اینکه میزان پیشرفت ناشناخته است اما کار هنوز فعال است، ارزشمند است.
این چالش رابط کاربری گرافیکی با عنصر <progress>
موجود HTML کار کرد تا مقداری تلاش در دسترسی صرفه جویی کند. رنگها و طرحبندیها محدودیتهای سفارشیسازی عنصر داخلی را افزایش میدهند تا جزء را مدرنسازی کنند و آن را بهتر در سیستمهای طراحی قرار دهند.
نشانه گذاری
من انتخاب کردم که عنصر <progress>
را در یک <label>
بپیچم تا بتوانم از ویژگی های رابطه صریح به نفع یک رابطه ضمنی صرف نظر کنم. من همچنین یک عنصر والد تحت تأثیر وضعیت بارگذاری را برچسب گذاری کرده ام، بنابراین فناوری های صفحه خوان می توانند آن اطلاعات را به کاربر منتقل کنند.
<progress></progress>
اگر value
وجود نداشته باشد، پیشرفت عنصر نامشخص است. ویژگی max
پیشفرض 1 است، بنابراین پیشرفت بین 0 و 1 است. برای مثال، با تنظیم max
روی 100، محدوده 0-100 تنظیم میشود. من ترجیح دادم در محدوده 0 و 1 باقی بمانم و مقادیر پیشرفت را به 0.5 یا 50% ترجمه کنم.
پیشرفت بسته بندی شده با برچسب
در یک رابطه ضمنی، یک عنصر پیشرفت با برچسبی مانند زیر پیچیده می شود:
<label>Loading progress<progress></progress></label>
در نسخه ی نمایشی خود من انتخاب کردم که برچسب را فقط برای صفحه خوان ها درج کنم. این کار با قرار دادن متن برچسب در یک <span>
و اعمال برخی از سبکها به آن بهگونهای انجام میشود که عملاً از صفحه خارج شود:
<label>
<span class="sr-only">Loading progress</span>
<progress></progress>
</label>
با CSS همراه زیر از WebAIM :
.sr-only {
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
width: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
}
منطقه تحت تاثیر پیشرفت بارگیری
اگر بینایی سالمی دارید، میتوان به راحتی یک شاخص پیشرفت را با عناصر مرتبط و مناطق صفحه مرتبط کرد، اما برای کاربرانی که بینایی ندارند، چندان واضح نیست. با اختصاص دادن ویژگی aria-busy
به بالاترین عنصری که پس از اتمام بارگیری تغییر می کند، این را بهبود بخشید. علاوه بر این، رابطه بین پیشرفت و منطقه بارگذاری را با aria-describedby
نشان دهید.
<main id="loading-zone" aria-busy="true">
…
<progress aria-describedby="loading-zone"></progress>
</main>
از جاوا اسکریپت، در شروع کار aria-busy
را به true
و پس از اتمام به false
تغییر دهید.
اضافات صفت آریا
در حالی که نقش ضمنی عنصر <progress>
progressbar
است، من آن را برای مرورگرهایی که فاقد آن نقش ضمنی هستند، صریح کردهام. من همچنین ویژگی indeterminate
را اضافه کرده ام تا به صراحت عنصر را در حالت ناشناخته قرار دهم، که واضح تر از مشاهده عنصر بدون مجموعه value
است.
<label>
Loading
<progress
indeterminate
role="progressbar"
aria-describedby="loading-zone"
tabindex="-1"
>unknown</progress>
</label>
از tabindex="-1"
برای قابل تمرکز کردن عنصر پیشرفت از جاوا اسکریپت استفاده کنید. این برای فناوری صفحهخوان مهم است، زیرا با توجه به پیشرفت به عنوان تغییر پیشرفت، به کاربر اعلام میکند که پیشرفت بهروزرسانیشده تا کجا رسیده است.
سبک ها
عنصر پیشرفت زمانی که صحبت از یک ظاهر طراحی می شود کمی مشکل است. عناصر HTML داخلی دارای بخشهای مخفی ویژهای هستند که انتخاب آنها ممکن است دشوار باشد و اغلب فقط مجموعه محدودی از ویژگیها را برای تنظیم ارائه میدهند.
طرح بندی
سبک های چیدمان به گونه ای در نظر گرفته شده اند که انعطاف پذیری در اندازه و موقعیت برچسب عنصر پیشرفت را فراهم کنند. یک حالت تکمیل ویژه اضافه شده است که می تواند یک نشانه بصری مفید، اما نه لازم باشد.
<progress>
چیدمان
عرض عنصر پیشرفت دست نخورده باقی می ماند تا بتواند با فضای مورد نیاز در طراحی کوچک شده و رشد کند. استایلهای داخلی با تنظیم appearance
و border
بر روی none
، حذف میشوند. این کار به این دلیل انجام می شود که عنصر بتواند در مرورگرها عادی شود، زیرا هر مرورگر سبک های خاص خود را برای عنصر خود دارد.
progress {
--_track-size: min(10px, 1ex);
--_radius: 1e3px;
/* reset */
appearance: none;
border: none;
position: relative;
height: var(--_track-size);
border-radius: var(--_radius);
overflow: hidden;
}
مقدار 1e3px
برای _radius
از نماد علمی اعداد برای بیان یک عدد بزرگ استفاده می کند، بنابراین border-radius
همیشه گرد است. معادل 1000px
است. من دوست دارم از این استفاده کنم زیرا هدف من این است که از مقداری به اندازه کافی بزرگ استفاده کنم که بتوانم آن را تنظیم کنم و فراموش کنم (و نوشتن آن کوتاه تر از 1000px
است). در صورت نیاز بزرگتر کردن آن نیز آسان است: فقط 3 را به 4 تغییر دهید، سپس 1e4px
معادل 10000px
است.
overflow: hidden
استفاده می شود و سبکی بحث برانگیز بوده است. چند چیز را آسان کرد، مانند عدم نیاز به انتقال مقادیر border-radius
به مسیر، و عناصر پر کردن مسیر. اما این بدان معناست که هیچ فرزندانی از پیشرفت نمی توانند خارج از عنصر زندگی کنند. تکرار دیگری در مورد این عنصر پیشرفت سفارشی میتواند بدون overflow: hidden
و ممکن است فرصتهایی را برای انیمیشنها یا وضعیتهای تکمیل بهتر باز کند.
پیشرفت کامل شد
انتخابگرهای CSS کار سختی را در اینجا با مقایسه حداکثر با مقدار انجام می دهند و اگر مطابقت داشته باشند، پیشرفت کامل می شود. پس از تکمیل، یک شبه عنصر تولید می شود و به انتهای عنصر پیشرفت اضافه می شود، که یک نشانه بصری اضافی برای تکمیل ارائه می دهد.
progress:not([max])[value="1"]::before,
progress[max="100"][value="100"]::before {
content: "✓";
position: absolute;
inset-block: 0;
inset-inline: auto 0;
display: flex;
align-items: center;
padding-inline-end: max(calc(var(--_track-size) / 4), 3px);
color: white;
font-size: calc(var(--_track-size) / 1.25);
}
رنگ
مرورگر رنگ های خود را برای عنصر پیشرفت می آورد و تنها با یک ویژگی CSS با نور و تاریکی سازگار است. این را می توان با برخی از انتخابگرهای خاص مرورگر ایجاد کرد.
سبک مرورگر روشن و تاریک
برای انتخاب سایت خود به عنصر <progress>
تطبیقی تیره و روشن، color-scheme
تنها چیزی است که لازم است.
progress {
color-scheme: light dark;
}
پیشرفت ملک تک رنگ پر شده است
برای رنگ آمیزی عنصر <progress>
، از accent-color
استفاده کنید.
progress {
accent-color: rebeccapurple;
}
توجه کنید که رنگ پسزمینه آهنگ از روشن به تیره بسته به accent-color
تغییر میکند. مرورگر کنتراست مناسب را تضمین می کند: بسیار تمیز.
رنگ های روشن و تیره کاملا سفارشی
دو ویژگی سفارشی را روی عنصر <progress>
تنظیم کنید، یکی برای رنگ آهنگ و دیگری برای رنگ پیشرفت مسیر. در داخل پرس و جو رسانه prefers-color-scheme
، مقادیر رنگ جدیدی را برای مسیر و ردیابی پیشرفت ارائه دهید.
progress {
--_track: hsl(228 100% 90%);
--_progress: hsl(228 100% 50%);
}
@media (prefers-color-scheme: dark) {
progress {
--_track: hsl(228 20% 30%);
--_progress: hsl(228 100% 75%);
}
}
سبک های تمرکز
قبلاً به عنصر یک فهرست برگه منفی داده بودیم تا بتوان آن را از نظر برنامهریزی متمرکز کرد. از :focus-visible
برای سفارشی کردن فوکوس برای انتخاب سبک حلقه فوکوس هوشمندتر استفاده کنید. با این کار، کلیک و فوکوس ماوس حلقه فوکوس را نشان نمیدهد، اما کلیکهای صفحه کلید نشان میدهد. ویدئوی یوتیوب عمیقتر به این موضوع میپردازد و ارزش بررسی را دارد.
progress:focus-visible {
outline-color: var(--_progress);
outline-offset: 5px;
}
سبک های سفارشی در مرورگرها
با انتخاب بخشهایی از عنصر <progress>
که هر مرورگر نمایش میدهد، استایلها را سفارشی کنید. استفاده از عنصر پیشرفت یک تگ است، اما از چند عنصر فرزند ساخته شده است که از طریق شبه انتخابگرهای CSS در معرض دید قرار میگیرند. اگر این تنظیمات را فعال کنید، Chrome DevTools این عناصر را به شما نشان می دهد:
- روی صفحه خود کلیک راست کرده و Inspect Element را انتخاب کنید تا DevTools ظاهر شود.
- روی چرخ دنده تنظیمات در گوشه سمت راست بالای پنجره DevTools کلیک کنید.
- در زیر عنوان Elements ، چک باکس Show user agent shadow DOM را پیدا کرده و فعال کنید.
سبک های سافاری و کرومیوم
مرورگرهای مبتنی بر WebKit مانند Safari و Chromium ::-webkit-progress-bar
و ::-webkit-progress-value
را در معرض دید قرار می دهند که امکان استفاده از زیرمجموعه ای از CSS را فراهم می کند. در حال حاضر، background-color
با استفاده از ویژگیهای سفارشی ایجاد شده قبلی، که با روشنایی و تاریکی سازگار است، تنظیم کنید.
/* Safari/Chromium */
progress[value]::-webkit-progress-bar {
background-color: var(--_track);
}
progress[value]::-webkit-progress-value {
background-color: var(--_progress);
}
سبک های فایرفاکس
فایرفاکس فقط انتخابگر شبه ::-moz-progress-bar
در عنصر <progress>
نشان می دهد. این همچنین به این معنی است که ما نمیتوانیم مسیر را مستقیماً رنگ آمیزی کنیم.
/* Firefox */
progress[value]::-moz-progress-bar {
background-color: var(--_progress);
}
توجه داشته باشید که فایرفاکس دارای یک رنگ تراک از accent-color
است در حالی که iOS Safari یک مسیر آبی روشن دارد. در حالت تاریک هم همینطور است: فایرفاکس یک مسیر تیره دارد، اما رنگ سفارشیای که ما تنظیم کردهایم نیست، و در مرورگرهای مبتنی بر Webkit کار میکند.
انیمیشن
هنگام کار با شبه انتخابگرهای داخلی مرورگر، اغلب با مجموعه محدودی از خصوصیات مجاز CSS است.
متحرک سازی مسیر پر شدن
افزودن یک انتقال به inline-size
عنصر پیشرفت برای Chromium کار می کند اما برای Safari نه. فایرفاکس همچنین از ویژگی انتقال در ::-moz-progress-bar
خود استفاده نمی کند.
/* Chromium Only 😢 */
progress[value]::-webkit-progress-value {
background-color: var(--_progress);
transition: inline-size .25s ease-out;
}
متحرک سازی حالت :indeterminate
در اینجا من کمی خلاق تر می شوم تا بتوانم یک انیمیشن ارائه کنم. یک شبه عنصر برای Chromium ایجاد میشود و یک گرادیان اعمال میشود که برای هر سه مرورگر متحرک جلو و عقب میشود.
خواص سفارشی
ویژگی های سفارشی برای بسیاری از چیزها عالی هستند، اما یکی از موارد مورد علاقه من به سادگی نام گذاری یک مقدار CSS جادویی است. زیر یک linear-gradient
نسبتاً پیچیده است، اما با نامی زیبا. هدف و موارد استفاده آن را می توان به وضوح درک کرد.
progress {
--_indeterminate-track: linear-gradient(to right,
var(--_track) 45%,
var(--_progress) 0%,
var(--_progress) 55%,
var(--_track) 0%
);
--_indeterminate-track-size: 225% 100%;
--_indeterminate-track-animation: progress-loading 2s infinite ease;
}
ویژگیهای سفارشی همچنین به خشک ماندن کد کمک میکند، زیرا یک بار دیگر، نمیتوانیم این انتخابگرهای خاص مرورگر را با هم گروهبندی کنیم.
فریم های کلیدی
هدف یک انیمیشن بی نهایت است که به عقب و جلو می رود. فریم های کلیدی شروع و پایان در CSS تنظیم می شوند. فقط یک فریم کلیدی مورد نیاز است، فریم کلیدی میانی با 50%
، برای ایجاد انیمیشنی که بارها و بارها به جایی که از آنجا شروع شده برمی گردد!
@keyframes progress-loading {
50% {
background-position: left;
}
}
هدف قرار دادن هر مرورگر
هر مرورگری اجازه ایجاد شبه عناصر را در خود عنصر <progress>
نمی دهد یا امکان متحرک سازی نوار پیشرفت را فراهم نمی کند. مرورگرهای بیشتری نسبت به عناصر شبه از متحرک سازی مسیر پشتیبانی می کنند، بنابراین من از شبه عناصر به عنوان پایه و به نوارهای متحرک ارتقاء می دهم.
شبه عنصر کروم
کروم به شبه عنصر اجازه می دهد: ::after
استفاده با موقعیتی برای پوشش عنصر. از ویژگی های سفارشی نامشخص استفاده می شود و انیمیشن عقب و جلو بسیار خوب کار می کند.
progress:indeterminate::after {
content: "";
inset: 0;
position: absolute;
background: var(--_indeterminate-track);
background-size: var(--_indeterminate-track-size);
background-position: right;
animation: var(--_indeterminate-track-animation);
}
نوار پیشرفت سافاری
برای Safari، ویژگی های سفارشی و یک انیمیشن در نوار پیشرفت شبه عنصر اعمال می شود:
progress:indeterminate::-webkit-progress-bar {
background: var(--_indeterminate-track);
background-size: var(--_indeterminate-track-size);
background-position: right;
animation: var(--_indeterminate-track-animation);
}
نوار پیشرفت فایرفاکس
برای فایرفاکس، ویژگی های سفارشی و یک انیمیشن نیز در نوار پیشرفت شبه عنصر اعمال می شود:
progress:indeterminate::-moz-progress-bar {
background: var(--_indeterminate-track);
background-size: var(--_indeterminate-track-size);
background-position: right;
animation: var(--_indeterminate-track-animation);
}
جاوا اسکریپت
جاوا اسکریپت نقش مهمی با عنصر <progress>
ایفا می کند. مقدار ارسال شده به عنصر را کنترل می کند و اطمینان حاصل می کند که اطلاعات کافی در سند برای صفحه خوان ها وجود دارد.
const state = {
val: null
}
نسخه ی نمایشی دکمه هایی را برای کنترل پیشرفت ارائه می دهد. آنها state.val
را به روز می کنند و سپس تابعی را برای به روز رسانی DOM فراخوانی می کنند.
document.querySelector('#complete').addEventListener('click', e => {
state.val = 1
setProgress()
})
setProgress()
این تابع جایی است که ارکستراسیون UI/UX رخ می دهد. با ایجاد تابع setProgress()
شروع کنید. هیچ پارامتری لازم نیست زیرا به شیء state
، عنصر پیشرفت و منطقه <main>
دسترسی دارد.
const setProgress = () => {
}
تنظیم وضعیت بارگیری در منطقه <main>
بسته به اینکه پیشرفت کامل شده باشد یا خیر، عنصر <main>
مربوط به ویژگی aria-busy
به روز رسانی نیاز دارد:
const setProgress = () => {
zone.setAttribute('aria-busy', state.val < 1)
}
اگر مقدار بارگیری ناشناخته است، ویژگی ها را پاک کنید
اگر مقدار ناشناخته است یا تنظیم نشده است، در این استفاده null
، value
و ویژگی های aria-valuenow
را حذف کنید. با این کار <progress>
به نامعین تبدیل می شود.
const setProgress = () => {
zone.setAttribute('aria-busy', state.val < 1)
if (state.val === null) {
progress.removeAttribute('aria-valuenow')
progress.removeAttribute('value')
progress.focus()
return
}
}
مشکلات ریاضی اعشاری جاوا اسکریپت را برطرف کنید
از آنجایی که من ترجیح دادم به پیشفرض حداکثر ۱ پایبند باشم، توابع دمو افزایش و کاهش از ریاضی اعشاری استفاده میکنند. جاوا اسکریپت و سایر زبان ها همیشه در این کار عالی نیستند . در اینجا یک تابع roundDecimals()
است که مازاد نتیجه ریاضی را کاهش می دهد:
const roundDecimals = (val, places) =>
+(Math.round(val + "e+" + places) + "e-" + places)
مقدار را گرد کنید تا قابل ارائه و خوانا باشد:
const setProgress = () => {
zone.setAttribute('aria-busy', state.val < 1)
if (state.val === null) {
progress.removeAttribute('aria-valuenow')
progress.removeAttribute('value')
progress.focus()
return
}
const val = roundDecimals(state.val, 2)
const valPercent = val * 100 + "%"
}
مقدار را برای صفحه خوان ها و وضعیت مرورگر تنظیم کنید
مقدار در سه مکان در DOM استفاده می شود:
- ویژگی
value
عنصر<progress>
. - ویژگی
aria-valuenow
. - محتوای متن درونی
<progress>
.
const setProgress = () => {
zone.setAttribute('aria-busy', state.val < 1)
if (state.val === null) {
progress.removeAttribute('aria-valuenow')
progress.removeAttribute('value')
progress.focus()
return
}
const val = roundDecimals(state.val, 2)
const valPercent = val * 100 + "%"
progress.value = val
progress.setAttribute('aria-valuenow', valPercent)
progress.innerText = valPercent
}
توجه به پیشرفت
با به روز رسانی مقادیر، کاربران بینا تغییرات پیشرفت را مشاهده خواهند کرد، اما کاربران صفحه خوان هنوز اعلام تغییر را دریافت نکرده اند. عنصر <progress>
را متمرکز کنید و مرورگر به روز رسانی را اعلام می کند!
const setProgress = () => {
zone.setAttribute('aria-busy', state.val < 1)
if (state.val === null) {
progress.removeAttribute('aria-valuenow')
progress.removeAttribute('value')
progress.focus()
return
}
const val = roundDecimals(state.val, 2)
const valPercent = val * 100 + "%"
progress.value = val
progress.setAttribute('aria-valuenow', valPercent)
progress.innerText = valPercent
progress.focus()
}
نتیجه گیری
حالا که می دانید من چگونه این کار را انجام دادم، چگونه این کار را انجام می دهید‽🙂
مطمئناً چند تغییر وجود دارد که اگر فرصت دیگری به من داده شود، می خواهم انجام دهم. فکر میکنم فضایی برای پاک کردن مولفه فعلی وجود دارد، و فضایی برای تلاش برای ساختن یکی بدون محدودیتهای سبک شبه کلاس عنصر <progress>
وجود دارد. ارزش کاوش را دارد!
بیایید رویکردهایمان را متنوع کنیم و همه راههای ساخت در وب را بیاموزیم.
یک نسخه نمایشی ایجاد کنید، پیوندها را برای من توییت کنید ، و من آن را به بخش ریمیکس های انجمن در زیر اضافه می کنم!