הוספת מגע לאתר

מסכי מגע זמינים במכשירים רבים יותר, החל מטלפונים ועד למסכים במחשבים. האפליקציה צריכה להגיב למגע שלהם בצורה אינטואיטיבית ויפה.

מסכי מגע זמינים ביותר ויותר מכשירים, מטלפונים ועד מסכים של מחשבים. כשהמשתמשים בוחרים לבצע פעולות בממשק המשתמש, האפליקציה צריכה להגיב באופן אינטואיטיבי למשתמשים.

תגובה למצבים של רכיבים

האם אי פעם נגעתם או לחצתם על רכיב בדף אינטרנט ושאלתם את עצמכם אם האתר אכן זיהה אותו?

שינוי פשוט של צבע רכיב כשמשתמשים נוגעים בו או מבצעים אינטראקציה עם חלקים בממשק המשתמש שלכם נותן להם ביטחון בסיסי שהאתר פועל. כך תוכלו להפחית את תסכולם של המשתמשים, וגם ליצור תחושה של מהירות תגובה.

רכיבי DOM יכולים לרשת כל אחד מהמצבים הבאים: ברירת מחדל, פוקוס, מצב מעוף ומצב פעיל. כדי לשנות את ממשק המשתמש בכל אחת מהמצבויות האלה, צריך להחיל סגנונות על פסאודו-הקלאסות הבאות: :hover,‏ :focus ו-:active, כפי שמתואר בהמשך:

.btn {
  background-color: #4285f4;
}

.btn:hover {
  background-color: #296cdb;
}

.btn:focus {
  background-color: #0f52c1;

  /* The outline parameter suppresses the border
  color / outline when focused */
  outline: 0;
}

.btn:active {
  background-color: #0039a8;
}

רוצים לנסות?

תמונה שממחישה צבעים שונים למצבים שונים של לחצן

ברוב הדפדפנים בנייד, מצבי העברת העכבר ו/או מיקוד יחולו על רכיב אחרי שמקישים עליו.

חשוב לבחור בקפידה את הסגנונות שתגדירו ואת המראה שלהם בעיני המשתמש אחרי שהוא יסיים את המגע.

ביטול סגנונות ברירת המחדל של הדפדפן

אחרי שתוסיפו סגנונות למצבים השונים, תבחינו שרוב הדפדפנים מטמיעים סגנונות משלהם בתגובה למגע של המשתמש. הסיבה העיקרית לכך היא שבזמן ההשקה הראשונית של מכשירים ניידים, לאתרים מסוימים לא היה עיצוב למצב :active. כתוצאה מכך, בדפדפנים רבים נוספו צבע או סגנון הדגשה נוספים כדי לספק משוב למשתמש.

רוב הדפדפנים משתמשים במאפיין ה-CSS outline כדי להציג טבעת סביב רכיב כשהרכיב מקבל את המיקוד. אפשר לדכא אותו באמצעות:

.btn:focus {
    outline: 0;

    /* Add replacement focus styling here (i.e. border) */
}

דפדפני Safari ו-Chrome מוסיפים צבע הדגשה להקשה, שאפשר למנוע באמצעות מאפיין ה-CSS -webkit-tap-highlight-color:

/* Webkit / Chrome Specific CSS to remove tap
highlight color */
.btn {
  -webkit-tap-highlight-color: transparent;
}

רוצים לנסות?

ל-Internet Explorer ב-Windows Phone יש התנהגות דומה, אבל הוא מושתק באמצעות מטא תג:

<meta name="msapplication-tap-highlight" content="no">

יש ל-Firefox שתי תופעות לוואי שצריך לטפל בהן.

אפשר להסיר את המחלקה המדומה -moz-focus-inner, שמוסיפה קווי מתאר לרכיבים שאפשר לגעת בהם, על ידי הגדרה של border: 0.

אם משתמשים ברכיב <button> ב-Firefox, מופיע שיפוע. אפשר להסיר אותו על ידי הגדרת background-image: none.

/* Firefox Specific CSS to remove button
differences and focus ring */
.btn {
  background-image: none;
}

.btn::-moz-focus-inner {
  border: 0;
}

רוצים לנסות?

השבתת הבחירה על ידי משתמשים

כשאתם יוצרים את ממשק המשתמש, יכולים להיות תרחישים שבהם אתם רוצים שהמשתמשים יבצעו אינטראקציה עם הרכיבים שלכם, אבל אתם רוצים לבטל את התנהגות ברירת המחדל של בחירת טקסט בלחיצה ארוכה או גרירה של העכבר מעל ממשק המשתמש.

אפשר לעשות זאת באמצעות מאפיין ה-CSS user-select, אבל חשוב לזכור שמאוד מעצבן משתמשים אם הם רוצים לבחור את הטקסט ברכיב. לכן חשוב להשתמש בה בזהירות ובמידה.

/* Example: Disable selecting text on a paragraph element: */
p.disable-text-selection {
  user-select: none;
}

הטמעת תנועות בהתאמה אישית

אם יש לכם רעיון לאינטראקציות ולתנועות בהתאמה אישית לאתר, חשוב לזכור שני נושאים:

  1. איך תומכים בכל הדפדפנים
  2. איך לשמור על קצב פריימים גבוה.

במאמר הזה נתמקד בנושאים האלה, ונציג את ממשקי ה-API שאנחנו צריכים לתמוך בהם כדי להגיע לכל הדפדפנים. לאחר מכן נסביר איך אנחנו משתמשים באירועים האלה בצורה יעילה.

בהתאם למה שאתם רוצים שהמחווה תעשה, סביר להניח שתרצו שהמשתמש יתקשר עם רכיב אחד בכל פעם או שתהיה לו אפשרות לתקשר עם כמה רכיבים בו-זמנית.

במאמר הזה נבחן שתי דוגמאות, שתיהן מדגימות תמיכה בכל הדפדפנים ואת האופן שבו שומרים על קצב פריימים גבוה.

דוגמה לקובץ GIF של מגע במסמך

בדוגמה הראשונה, המשתמש יוכל לקיים אינטראקציה עם אלמנט אחד. במקרה כזה, ייתכן שתרצו שכל אירועי המגע יינתנו לאלמנט האחד הזה, כל עוד התנועה התחילה בהתחלה באלמנט עצמו. לדוגמה, אפשר להזיז את האצבע מהאלמנט שאפשר להחליק עליו ועדיין לשלוט בו.

האפשרות הזו שימושית כי היא מספקת למשתמשים גמישות רבה, אבל היא אוכפת הגבלה על האופן שבו המשתמשים יכולים לקיים אינטראקציה עם ממשק המשתמש.

דוגמה לקובץ GIF של מגע באלמנט

עם זאת, אם אתם מצפים שהמשתמשים יתנהלו עם כמה רכיבים בו-זמנית (באמצעות מגע רב-שכבתי), כדאי להגביל את המגע לרכיב הספציפי.

הגישה הזו גמישה יותר למשתמשים, אבל היא מסבכת את הלוגיקה של מניפולציה בממשק המשתמש, והיא פחות עמידת בשגיאות של משתמשים.

הוספת פונקציות event listener

ב-Chrome (מגרסה 55 ואילך), Internet Explorer ו-Edge, PointerEvents הן הגישה המומלצת ליישום תנועות מותאמות אישית.

בדפדפנים אחרים, TouchEvents ו-MouseEvents הם הגישה הנכונה.

היתרון הגדול של PointerEvents הוא שהוא משללב כמה סוגים של קלט, כולל אירועי עכבר, מגע ועט, לקבוצה אחת של קריאות חזרה (callbacks). האירועים שצריך להאזין להם הם pointerdown,‏ pointermove,‏ pointerup ו-pointercancel.

הערכים המקבילים בדפדפנים אחרים הם touchstart, ‏ touchmove,‏ touchend ו-touchcancel לאירועי מגע. אם רוצים להטמיע את אותה תנועה להזנת עכבר, צריך להטמיע את הערכים mousedown, ‏ mousemove ו-mouseup.

אם יש לכם שאלות לגבי האירועים שבהם כדאי להשתמש, תוכלו לעיין בטבלה הזו של אירועי מגע, עכבר ומצביע.

כדי להשתמש באירועים האלה, צריך להפעיל את השיטה addEventListener() על רכיב DOM, יחד עם שם האירוע, פונקציית קריאה חוזרת (callback) ומשתנה בוליאני. הערך הבוליאני קובע אם צריך לתפוס את האירוע לפני או אחרי שרכיבים אחרים יכלו לתפוס ולפרש את האירועים. (true מציין שרוצים שהאירוע יופיע לפני רכיבים אחרים).

דוגמה להאזנה להתחלת אינטראקציה.

// Check if pointer events are supported.
if (window.PointerEvent) {
  // Add Pointer Event Listener
  swipeFrontElement.addEventListener('pointerdown', this.handleGestureStart, true);
  swipeFrontElement.addEventListener('pointermove', this.handleGestureMove, true);
  swipeFrontElement.addEventListener('pointerup', this.handleGestureEnd, true);
  swipeFrontElement.addEventListener('pointercancel', this.handleGestureEnd, true);
} else {
  // Add Touch Listener
  swipeFrontElement.addEventListener('touchstart', this.handleGestureStart, true);
  swipeFrontElement.addEventListener('touchmove', this.handleGestureMove, true);
  swipeFrontElement.addEventListener('touchend', this.handleGestureEnd, true);
  swipeFrontElement.addEventListener('touchcancel', this.handleGestureEnd, true);

  // Add Mouse Listener
  swipeFrontElement.addEventListener('mousedown', this.handleGestureStart, true);
}

רוצים לנסות?

טיפול באינטראקציה עם רכיב יחיד

בקטע הקוד הקצר שלמעלה הוספנו רק את ה-event listener לאירועי העכבר. הסיבה לכך היא שאירועי עכבר מופעלים רק כשהסמן מרחף מעל הרכיב שאליו נוסף ה-event listener.

הפונקציה TouchEvents תעקוב אחרי תנועה אחרי שהיא תתחיל, ללא קשר למיקום המגע. הפונקציה PointerEvents תעקוב אחרי אירועים ללא קשר למיקום המגע, אחרי שנקרא לפונקציה setPointerCapture ברכיב DOM.

לאירועים של תנועת העכבר וסיום האירוע, מוסיפים את מאזיני האירועים ב שיטת ההתחלה של התנועות ומוסיפים את המאזינים למסמך, כך שהוא יכול לעקוב אחרי הסמן עד שהתנועה תושלם.

השלבים להטמעה הם:

  1. מוסיפים את כל רכיבי ה-event listener של TouchEvent ו-PointerEvent. ב-MouseEvents, מוסיפים רק את אירוע ההתחלה.
  2. בתוך פונקציית ה-callback של תנועת ההתחלה, מקשרים את אירועי העברת העכבר ואת אירועי הסיום למסמך. באופן הזה, כל אירועי העכבר מתקבלים, גם אם האירוע מתרחש ברכיב המקורי וגם אם לא. כדי לקבל את כל האירועים הבאים ב-PointerEvents, צריך להפעיל את setPointerCapture() על הרכיב המקורי. לאחר מכן מטפלים בהתחלת התנועה.
  3. טיפול באירועי ההעברה.
  4. באירוע הסיום, מסירים מהמסמך את האירועים של תנועת העכבר והאירוע של הסיום, ומסיימים את התנועות.

בהמשך מופיע קטע קוד של השיטה handleGestureStart() שמוסיפה למסמך את אירועי ההעברה והסיום:

// Handle the start of gestures
this.handleGestureStart = function(evt) {
  evt.preventDefault();

  if(evt.touches && evt.touches.length > 1) {
    return;
  }

  // Add the move and end listeners
  if (window.PointerEvent) {
    evt.target.setPointerCapture(evt.pointerId);
  } else {
    // Add Mouse Listeners
    document.addEventListener('mousemove', this.handleGestureMove, true);
    document.addEventListener('mouseup', this.handleGestureEnd, true);
  }

  initialTouchPos = getGesturePointFromEvent(evt);

  swipeFrontElement.style.transition = 'initial';
}.bind(this);

רוצים לנסות?

הקריאה החוזרת לסיום שאנחנו מוסיפים היא handleGestureEnd(), והיא מסירה מהמסמך את פונקציות ההעברה והסיום של מאזינים לאירוע, ולאחר מכן משחררת את תיעוד הסמן אחרי שהתנועה מסתיימת:

// Handle end gestures
this.handleGestureEnd = function(evt) {
  evt.preventDefault();

  if (evt.touches && evt.touches.length > 0) {
    return;
  }

  rafPending = false;

  // Remove Event Listeners
  if (window.PointerEvent) {
    evt.target.releasePointerCapture(evt.pointerId);
  } else {
    // Remove Mouse Listeners
    document.removeEventListener('mousemove', this.handleGestureMove, true);
    document.removeEventListener('mouseup', this.handleGestureEnd, true);
  }

  updateSwipeRestPosition();

  initialTouchPos = null;
}.bind(this);

רוצים לנסות?

על ידי מעקב אחר הדפוס הזה של הוספת אירוע ההעברה למסמך, אם המשתמש מתחיל לבצע אינטראקציה עם אלמנט ומעביר את התנועה שלו אל מחוץ לאלמנט, נמשיך לקבל תנועות עכבר ללא קשר למיקום שלו בדף, מכיוון שהאירועים מתקבלים מהמסמך.

בתרשים הזה מוצג מה קורה באירועי המגע כשאנחנו מוסיפים את אירועי ההזזה והסיום למסמך ברגע שהמחווה מתחילה.

איור של קישור אירועי מגע למסמך ב-`touchstart`

תגובה יעילה למגע

עכשיו, אחרי שטיפלנו באירועי ההתחלה והסיום, אנחנו יכולים להגיב לאירועי המגע.

אפשר לחלץ בקלות את x ו-y מכל אירוע של התחלה והעברה.

בדוגמה הבאה אנחנו בודקים אם האירוע הוא מ-TouchEvent, על ידי בדיקה אם targetTouches קיים. אם כן, המערכת מחלצת את הערכים של clientX ו-clientY מהמגע הראשון. אם האירוע הוא PointerEvent או MouseEvent, המערכת מחלצת את clientX ו-clientY ישירות מהאירוע עצמו.

function getGesturePointFromEvent(evt) {
    var point = {};

    if (evt.targetTouches) {
      // Prefer Touch Events
      point.x = evt.targetTouches[0].clientX;
      point.y = evt.targetTouches[0].clientY;
    } else {
      // Either Mouse event or Pointer Event
      point.x = evt.clientX;
      point.y = evt.clientY;
    }

    return point;
  }

רוצים לנסות?

ל-TouchEvent יש שלוש רשימות שמכילות נתוני מגע:

  • touches: רשימה של כל הנגיעות הנוכחיות במסך, ללא קשר לרכיב ה-DOM שהן מוצגות בו.
  • targetTouches: רשימת המגעים שנמצאים כרגע ברכיב ה-DOM שאליו האירוע קשור.
  • changedTouches: רשימת נקודות המגע שהשתנו וכתוצאה מכך האירוע הופעל.

ברוב המקרים, targetTouches מספק את כל מה שדרוש לכם. (למידע נוסף על הרשימות האלה, ראו רשימות מגע).

שימוש ב-requestAnimationFrame

מאחר שהקריאות החוזרות של האירועים מופעלות בשרשור הראשי, אנחנו רוצים להריץ כמה שפחות קוד בקריאות החוזרות של האירועים שלנו, כדי לשמור על קצב פריימים גבוה ולמנוע תנודות.

באמצעות requestAnimationFrame() יש לנו הזדמנות לעדכן את ממשק המשתמש ממש לפני שהדפדפן מתכוון לצייר מסגרת, וכך נוכל להעביר חלק מהעבודה מהקריאות החוזרות (callbacks) של האירועים.

אם אתם לא מכירים את requestAnimationFrame(), תוכלו לקרוא מידע נוסף כאן.

הטמעה אופיינית היא לשמור את הקואורדינטות x ו-y מאירועי ההתחלה וההעברה ולבקש פריים אנימציה בתוך הקריאה החוזרת של האירוע Transfer (העברה).

בדמו שלנו, אנחנו שומרים את מיקום המגע הראשוני ב-handleGestureStart() (מחפשים את initialTouchPos):

// Handle the start of gestures
this.handleGestureStart = function(evt) {
  evt.preventDefault();

  if (evt.touches && evt.touches.length > 1) {
    return;
  }

  // Add the move and end listeners
  if (window.PointerEvent) {
    evt.target.setPointerCapture(evt.pointerId);
  } else {
    // Add Mouse Listeners
    document.addEventListener('mousemove', this.handleGestureMove, true);
    document.addEventListener('mouseup', this.handleGestureEnd, true);
  }

  initialTouchPos = getGesturePointFromEvent(evt);

  swipeFrontElement.style.transition = 'initial';
}.bind(this);

השיטה handleGestureMove() שומרת את המיקום של האירוע שלה לפני שהיא מבקשת פריים של אנימציה, אם יש צורך בכך, ומעבירה את הפונקציה onAnimFrame() כקריאה חוזרת:

this.handleGestureMove = function (evt) {
  evt.preventDefault();

  if (!initialTouchPos) {
    return;
  }

  lastTouchPos = getGesturePointFromEvent(evt);

  if (rafPending) {
    return;
  }

  rafPending = true;

  window.requestAnimFrame(onAnimFrame);
}.bind(this);

הערך onAnimFrame הוא פונקציה שמשתנה כשמפעילים אותה, כדי להזיז את ממשק המשתמש. כשאנחנו מעבירים את הפונקציה הזו אל requestAnimationFrame(), אנחנו אומרים לדפדפן לבצע קריאה אליה ממש לפני שהוא עומד לעדכן את הדף (כלומר, לצייר את השינויים בדף).

בקריאה החוזרת (callback) של handleGestureMove(), אנחנו בודקים קודם אם הערך של rafPending הוא false, כדי לבדוק אם requestAnimationFrame() קרא ל-onAnimFrame() מאז אירוע ההזזה האחרון. המשמעות היא שיש לנו רק requestAnimationFrame() אחד שממתין להפעלה בכל רגע נתון.

כשפונקציית ה-callback‏ onAnimFrame() מופעלת, אנחנו מגדירים את הטרנספורמציה לכל הרכיבים שאנחנו רוצים להעביר לפני שאנחנו מעדכנים את rafPending ל-false, וכך מאפשרים לאירוע המגע הבא לבקש פריים חדש של אנימציה.

function onAnimFrame() {
  if (!rafPending) {
    return;
  }

  var differenceInX = initialTouchPos.x - lastTouchPos.x;
  var newXTransform = (currentXPosition - differenceInX)+'px';
  var transformStyle = 'translateX('+newXTransform+')';

  swipeFrontElement.style.webkitTransform = transformStyle;
  swipeFrontElement.style.MozTransform = transformStyle;
  swipeFrontElement.style.msTransform = transformStyle;
  swipeFrontElement.style.transform = transformStyle;

  rafPending = false;
}

שליטה בתנועות באמצעות פעולות מגע

המאפיין touch-action ב-CSS מאפשר לכם לקבוע את התנהגות ברירת המחדל של רכיב במגע. בדוגמאות שלנו אנחנו משתמשים ב-touch-action: none כדי למנוע מהדפדפן לבצע פעולה כלשהי בעקבות מגע של משתמש, וכך לאפשר לנו ליירט את כל אירועי המגע.

/* Pass all touches to javascript: */
button.custom-touch-logic {
  touch-action: none;
}

השימוש ב-touch-action: none הוא אפשרות גרעינית במידה מסוימת כי הוא מונע את כל התנהגויות ברירת המחדל של הדפדפן. במקרים רבים אחת מהאפשרויות הבאות היא פתרון טוב יותר.

touch-action מאפשרת להשבית את התנועות שהדפדפן מטמיע. לדוגמה, ב-IE10 ואילך יש תמיכה בהקשה כפולה כדי לבצע פעולת זום. הגדרה של touch-action של manipulation מונעת את התנהגות ברירת המחדל של הקשה כפולה.

כך תוכלו להטמיע בעצמכם תנועת הקשה כפולה.

בהמשך מופיעה רשימה של ערכי touch-action נפוצים:

פרמטרים של פעולות מגע
touch-action: none הדפדפן לא יטפל באינטראקציות מגע.
touch-action: pinch-zoom ההגדרה משביתה את כל האינטראקציות בדפדפן, למשל: 'touch-action: none' מלבד 'pitch-zoom', שעדיין מטופלת על ידי הדפדפן.
touch-action: pan-y pinch-zoom טיפול בגלילות אופקיות ב-JavaScript בלי להשבית את הגלילה האנכית או את התכונה &#39;הגדלת התמונה באמצעות צביטה&#39; (למשל קרוסלות של תמונות).
touch-action: manipulation ההגדרה משביתה את תנועת הקשה כפולה שמונעת עיכובים של הקליקים על ידי הדפדפן. עוזבים את הגלילה ואת שינוי מרחק התצוגה באמצעות צביטה, ומגיעים לדפדפן.

תמיכה בגרסאות ישנות יותר של IE

אם רוצים לתמוך ב-IE10, צריך לטפל בגרסאות של PointerEvents עם תחילית של ספק.

כדי לבדוק אם יש תמיכה ב-PointerEvents, בדרך כלל מחפשים את הערך window.PointerEvent, אבל ב-IE10 מחפשים את הערך window.navigator.msPointerEnabled.

שמות האירועים עם הקידומות של הספקים הם: 'MSPointerDown',‏ 'MSPointerUp' ו-'MSPointerMove'.

בדוגמה הבאה אפשר לראות איך בודקים אם יש תמיכה ומשנים את שמות האירועים.

var pointerDownName = 'pointerdown';
var pointerUpName = 'pointerup';
var pointerMoveName = 'pointermove';

if (window.navigator.msPointerEnabled) {
  pointerDownName = 'MSPointerDown';
  pointerUpName = 'MSPointerUp';
  pointerMoveName = 'MSPointerMove';
}

// Simple way to check if some form of pointerevents is enabled or not
window.PointerEventsSupport = false;
if (window.PointerEvent || window.navigator.msPointerEnabled) {
  window.PointerEventsSupport = true;
}

מידע נוסף זמין במאמר העדכונים הזה של Microsoft.

חומרי עזר

פסאודו מחלקות למצבי מגע

מחלקה דוגמה תיאור
:מעבר בריחוף
לחצן במצב לחיצה
האירוע מתרחש כשהסמן מוצב מעל רכיב. שינויים בממשק המשתמש במצב של העברת העכבר מעל הרכיבים עוזרים לעודד את המשתמשים לבצע פעולות עם הרכיבים.
:התמקדות
לחצן במצב מיקוד
מופיעים כשהמשתמש עובר בין רכיבים בדף. מצב המיקוד מאפשר למשתמש לדעת איזה רכיב הוא מפעיל כרגע, וגם לנווט בממשק המשתמש בקלות באמצעות מקלדת.
‎:active
לחצן במצב לחוץ
האירוע הזה מתרחש כשמשתמשים בוחרים אלמנט, למשל כשהם לוחצים עליו או נוגעים בו.

המסמך המקיף ביותר בנושא אירועי מגע זמין כאן: אירועי מגע של W3C.

אירועי מגע, עכבר וסמן

האירועים האלה הם אבני הבניין להוספת תנועות חדשות לאפליקציה:

אירועים של מגע, עכבר או מצביע
touchstart, mousedown, pointerdown האירוע הזה נקרא כשאצבע נוגעת לראשונה ברכיב או כשהמשתמש לוחץ למטה על העכבר.
touchmove, mousemove, pointermove האירוע הזה נקרא כשהמשתמש מזיז את האצבע על המסך או גורר בעזרת העכבר.
touchend, mouseup, pointerup האירוע הזה נקרא כשהמשתמש מרים את האצבע מהמסך או משחרר את העכבר.
touchcancel pointercancel הקריאה הזו מתבצעת כשהדפדפן מבטל את תנועות המגע. לדוגמה, משתמש מגע באפליקציית אינטרנט ואז עובר בין כרטיסיות.

רשימות מגע

כל אירוע מגע כולל שלושה מאפייני רשימה:

מאפייני אירועי מגע
touches רשימה של כל הנגיעות הנוכחיות במסך, ללא קשר לפריטים שנוגעים בהם.
targetTouches רשימה של נגיעות שהתחילו ברכיב שהוא היעד של האירוע הנוכחי. לדוגמה, אם אתם מחייבים אתכם ל-<button>, תקבלו כרגע רק נגיעות בלחצן הזה. אם תקשרו למסמך, תקבלו את כל המגעים שקיימים כרגע במסמך.
changedTouches רשימת נקודות המגע שהשתנו וכתוצאה מכך האירוע הופעל:
  • באירוע touchstart – רשימה של נקודות המגע שהפכו לפעילות עם האירוע הנוכחי.
  • באירוע touchmove – רשימה של נקודות המגע שהועברו מאז האירוע הקודם.
  • לגבי האירועים touchend ו- touchcancel – רשימה של נקודות המגע שהוסרו מהפלטפורמה.

הפעלת תמיכה במצב פעיל ב-iOS

לצערנו, ב-Safari ל-iOS המצב active לא מיושם כברירת מחדל. כדי שהמצב יפעל, צריך להוסיף מאזין לאירועים מסוג touchstart לגוף המסמך או לכל רכיב.

צריך לעשות זאת מאחורי בדיקת סוכן משתמש כדי שהיא תפעל רק במכשירי iOS.

היתרון של הוספת התחלת מגע לגוף הוא החלה על כל הרכיבים ב-DOM, אבל הן עשויות להוביל לבעיות בביצועים כשגוללים את הדף.

window.onload = function() {
  if (/iP(hone|ad)/.test(window.navigator.userAgent)) {
    document.body.addEventListener('touchstart', function() {}, false);
  }
};

האפשרות החלופית היא להוסיף את רכיבי ההקשה להתחלת האינטראקציה לכל הרכיבים בדף שאפשר לבצע איתם אינטראקציה, וכך לצמצם חלק מהבעיות שקשורות לביצועים.

window.onload = function() {
  if (/iP(hone|ad)/.test(window.navigator.userAgent)) {
    var elements = document.querySelectorAll('button');
    var emptyFunction = function() {};

    for (var i = 0; i < elements.length; i++) {
        elements[i].addEventListener('touchstart', emptyFunction, false);
    }
  }
};