תחיליות והטיפול בהן

לפעמים עלינו להשתמש בתחיליות על מנת לגרום ל-CSS3 לעבוד. אני מפרט שלוש דרכים עיקריות להתמודדות עם זה.
CSS3 icon

במאמר הקודם על CSS3 דיברתי גבוהה-גבוהה על 2d transform שזה מעולה. כל מי שהיה חמוש בפיירפוקס, כרום ואפילו אקספלורר מגרסה 10 ומעלה יכול היה להנות מהדמו. אבל מי שניגש למאמר באמצעות טלפון נייד עם אנדרואיד מגרסה 4.4.4 ומטה או iOS מגרסה 8.3 ומטה, היה רואה את ה-divים ללא transition ואת האנימציה לא זזה. אם אתם לא מאמינים לי, אתם מוזמנים לנסות עם הטלפון שלכם ולהכנס למאמר ולראות שדבר לא עובד.

גם אנדרואיד וגם ספארי תומכים ב-2d transform, אבל הצצה מהירה ב-caniuse מראה שהם נתמכים רק על ידי שימוש ב webkit prefixes.

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

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

ככה נראות תחיליות בנוגע ל-transition. לכל דפדפן יש את התחילית שלו – אופרה, אקספלורר, פיירפוקס ו-וובקיט. בסוף נהוג לשים את התכונה ללא התחילית.

-o-transition: all 1s linear;
-ms-transition: all 1s linear;
-moz-transition: all 1s linear;
-webkit-transition: all 1s linear;
transition: all 1s linear;

כשאני משתמש ב-CSS3, לפעמים אני נדרש לשים תחילית – תלוי בדפדפן. השאלה הנשאלת היא איך בדיוק לעשות את זה? אני תמיד יכול לבדוק באתרים כמו caniuse ולראות אם צריך, או להסתמך על ה-QA. אבל זה לא באמת עסק. יש לנו 8 סוגי דפדפנים שונים. ועם האנדרואיד והספארי שמותקנים על ניידים שונים, החגיגה גדלה.

יש כל מיני שיטות לטפל בנושא התחיליות.

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

דרך אחת שאני מעדיף להוריד לעצמי עין מלהשתמש בה היא prefix free – קובץ JS שיושב באפליקציה ובאופן אוטומטי מוסיף את התחיליות בהתאם לדפדפן. העבודה שם היא קלה במיוחד. כל מה שצריך זה להוסיף קובץ JS ו… זהו. הסקריפט ידאג אוטומטית בזמן אמת להוסיף את התחיליות.

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


[שימו את השיר הזה בפול ווליום במשרד. מרגישים מבוכה? הבוס מסתכל עליכם מוזר? חברי הצוות מתלחששים? זה בדיוק, אבל בדיוק מה שיקרה לכם אם תשתמשו ב-prefixfree]

דרך ולידית, אבל מבאסת

דרך נוספת, אם אתם משתמשים ב-LESS או ב-SASS היא להוסיף את התחיליות עם mixin. משהו בסגנון הזה:

@mixin prefix($property, $value, $vendors: webkit moz ms o) {
      @if $vendors {
        @each $vendor in $vendors {
          #{'-' + $vendor + '-' + $property}: #{$value};
        }
      }
      #{$property}: #{$value};
}

כדי לקרוא לזה, אני צריך לעשות את זה:

.element {
  @include prefix(transform, rotate(45deg), webkit ms);
}

זו דרך וולידית, אבל קצת מייאשת. כי בכל זאת צריך לזכור לקרוא למיקסין.

הדרך הטובה

הדרך הטובה יותר, שבה אני משתמש היא להשתמש ב-Grunt ולעשות preprocessing לאפליקציה שלי, כך שהתחיליות יוספו באופן אוטומטי לפי בחירתי. אם אני רוצה לתמוך באנדרואיד מגרסה 4 ולהוסיף לו תחיליות, אני אעשה את זה. אם אני רוצה לתמוך רק בספארי מגרסה מסוימת, אני אעשה את זה. הכל לבחירתי והכל כחלק אוטומטי מתהליך ה-build. גם כך אני מריץ תהליכי uglify על ה-CSS שלי, אין לי בעיה להוסיף תהליכים נוספים. אם אתם לא מכירים grunt, זה יכול להשמע לכם כמו סינית מדוברת. אבל חבל, אולי כדאי להשקיע מספר דקות ולקרוא את המאמר שבו אני מסביר על grunt, להתנסות וללמוד כי בסופו של דבר זה העתיד.

אז איך זה עובד? אני כותב את ה-CSS שלי כרגיל, ללא שום תחיליות וללא שום מחשבה. יש לי Grunt שרץ בכל פעם שאני שומר את קבצי ה-CSS שלי. ה-grunt הזה עושה כל מיני משימות שאחת מהן היא postcss – מעבר על קבצי ה-CSS שלי ותיקונם. postcss הוא מודול node.js שמתחבר ל-grunt ועובד איתו. הוא יכול להכיל עוד מודולים רבים. אחד מהם הוא Autoprefixer שעושה בדיוק את מה שתיארתי.

אז קודם כל נוודא שיש לנו grunt. אחרי זה נתקין בתיקית הפרויקט שלנו את postcss ואת autoprefixer:

npm install grunt-postcss autoprefixer-core

אחרי זה, אנו צריכים להגדיר את ה-Gruntfile.js. הוא נראה כך:

module.exports = function(grunt) {

	grunt.initConfig({
	  postcss: {
	    options: {
	      processors: [
		require('autoprefixer-core')({browsers: ['last 2 versions', 'Android >= 2.3']}), // add vendor prefixes
	      ]
	    },
	    main: {
		src: 'source/*.css', //source
		dest: 'css/*.css' //destination of compiled css
	    }
	  }
	});

	grunt.loadNpmTasks('grunt-postcss');

};

זה מה שיפעיל אך ורק את autoprefixes. אפשר גם להוסיף את השורה הזו כדי להכריז על postcss כ-default וכך בעצם להמנע מלכתוב grunt postcss אלא לכתוב רק grunt.

grunt.registerTask('default', ['postcss']);

כאשר אני אריץ את ה-grunt הזה, הוא יקח את כל קבצי ה-CSS שנמצאים ב-source, יבדוק את caniuse בהתאם לקריטריונים שבחרתי ויוסיף תחיליות איפה שצריך ויכתוב את קבצי ה-CSS עם התחיליות בתיקית CSS. איזה קריטריונים בחרתי? זה מופיע ב-gruntfile ממש למעלה. הנה, אכתוב את זה שוב:

{browsers: ['last 2 versions', 'Android >= 2.3']}

אם הכל תקין, כך זה יראה (במידה ויש רק קובץ CSS אחד) :

$ grunt Running "postcss:main" (postcss) task >> 1 processed stylesheet created.  Done, without errors.
הרצת grunt autoprefixer על CSS
$ grunt
Running "postcss:main" (postcss) task
>> 1 processed stylesheet created.

Done, without errors.

אם אסתכל על התוכן, אז ככה זה נראה לפני:

.all_divs {
	background-color: red;
	color: white;
	height: 100px;
	width: 100px;
}
.div_sanbox {
  height: 200px;
  width: 100%;
}
#mydiv02 {	
	        transform: scale(1.2,1.2); 
}

#mydiv03 {
	        transform: rotate(20deg); 
}
#mydiv04 {
	
	        transform: skew(30deg, 0deg); 
}
#mydiv05 {
	
	        transform: skew(-30deg, 0deg); 
}
#mydiv06 {

	        transform: skew(0deg, 30deg); 
}
#mydiv07 {
	
	        transform: skew(0deg, -30deg); 
} 
#mydiv08 {
	
	        transform: translate(-50px,20px); 
}

וככה זה נראה אחרי ההרצה:

.all_divs {
	background-color: red;
	color: white;
	height: 100px;
	width: 100px;
}
.div_sanbox {
  height: 200px;
  width: 100%;
}
#mydiv02 {	
	        -webkit-transform: scale(1.2,1.2);	
	                transform: scale(1.2,1.2); 
}

#mydiv03 {
	        -webkit-transform: rotate(20deg);
	                transform: rotate(20deg); 
}
#mydiv04 {
	
	        -webkit-transform: skew(30deg, 0deg);
	
	                transform: skew(30deg, 0deg); 
}
#mydiv05 {
	
	        -webkit-transform: skew(-30deg, 0deg);
	
	                transform: skew(-30deg, 0deg); 
}
#mydiv06 {

	        -webkit-transform: skew(0deg, 30deg);

	                transform: skew(0deg, 30deg); 
}
#mydiv07 {
	
	        -webkit-transform: skew(0deg, -30deg);
	
	                transform: skew(0deg, -30deg); 
} 
#mydiv08 {
	
	        -webkit-transform: translate(-50px,20px);
	
	                transform: translate(-50px,20px); 
}

והנה אחת הדוגמאות מהמאמר על ה-transform. אבל היא גם תעבוד בנייד. בידקו ותהנו!

נשאלת השאלה – מה? עכשיו אני אצטרך להפעיל את grunt בכל פעם שאני מכניס סלקטור ל-CSS שלי? התשובה היא לא. למה שלא נדאג ש-Grunt יופעל אוטומטית בכל פעם שאני אעשה שינוי כלשהו בקבצי ה-CSS? קל לדאוג לזה באמצעות שימוש ב Grunt watch.

פוסטים נוספים שכדאי לקרוא

פתרונות ומאמרים על פיתוח אינטרנט

יישום של nonce על מנת להגן מפני התקפות injection

בפוסט הקודם הסברתי על hash עם CSP על משאבי inline – שזה נחמד ומעולה אבל פחות ישים בעולם האמיתי שבו בדרך כלל התוכן ה-inline (בין

גלילה לראש העמוד