var gulp = require('gulp'); // sass 插件 var sass = require('gulp-sass'); // 自動同步瀏覽器插件 var browserSync = require('browser-sync'); // 合併文件的插件 var useref = require('gulp-useref'); // 壓縮js插件 var uglify = require('gulp-uglify'); var gulpIf = require('gulp-if'); // 壓縮css插件 var cssnano = require('gulp-cssnano'); // 壓縮圖片插件 var imagemin = require('gulp-imagemin'); // 壓縮png圖片的插件 var pngquant = require('imagemin-pngquant'); // 緩存插件,能夠加快編譯速度 var cache = require('gulp-cache'); // 刪除文件插件 var del = require('del'); // 同步運行任務插件 var runSequence = require('run-sequence'); // 給css3屬性添加瀏覽器前綴插件 var autoprefixer = require('gulp-autoprefixer'); // sourcemap 插件 var sourcemaps = require('gulp-sourcemaps'); var lazypipe = require('lazypipe'); // 合成sprite圖片插件 var spritesmith = require('gulp.spritesmith'); var imageminOptipng = require('imagemin-optipng'); // 編譯sass文件,添加css3屬性瀏覽器前綴,reload 瀏覽器 gulp.task('sass', function () { return gulp.src('./src/scss/**/*.scss') .pipe(sass()) .pipe(autoprefixer()) .pipe(gulp.dest('./src/css')) .pipe(browserSync.reload({stream: true})); }); // 自動更新瀏覽器任務 gulp.task('browserSync', function () { browserSync.init({ server: { baseDir: 'src' } }) }); // 合併文件任務 // 在html設置須要合併的文件: // <!--build:js js/flexible.min.js --> // <script src="js/flexible_css.js"></script> // <script src="js/flexible.js"></script> // <!-- endbuild--> // 執行任務後,會編譯成 : <script src="js/flexible.min.js"></script> // 同時會把 flexible_css.js 和 flexible.js 合併成 flexible.min.js gulp.task('useref', function () { return gulp.src('./src/*.html') .pipe(useref({}, lazypipe().pipe(sourcemaps.init, { loadMaps: true }))) .pipe(gulpIf('*.js', uglify())) .pipe(gulpIf('*.css', cssnano())) .pipe(sourcemaps.write('maps')) .pipe(gulp.dest('dist')); }); // 圖片壓縮任務 gulp.task('images', function () { return gulp.src('./src/img/**/*.+(png|jpg|gif|svg)') .pipe(imagemin({ progressive: true, svgoPlugins: [{removeViewBox: false}], use: [pngquant()] })) .pipe(gulp.dest('dist/img')); }); // 合併sprite圖任務 gulp.task('sprite', function () { var spriteData = gulp.src('./src/img/sprite/**/*.png') .pipe(spritesmith({ imgName: 'sprite.png', cssName: 'sprite.scss', imgPath: '../img/sprite/sprite.png', cssFormat: 'scss', padding: 10 })); return spriteData.pipe(gulp.dest('./src/img/sprite/')) }); // 刪除build目錄 gulp.task('clean:dist', function () { return del.sync('dist'); }); // 清除緩存 gulp.task('cache:clear', function (cb) { return cache.clearAll(cb) }); // 監控任務,當有sass文件,html文件,js文件改動的時候,刷新瀏覽器 gulp.task('watch', ['browserSync', 'sass'], function () { gulp.watch('./src/scss/**/*.scss', ['sass']); gulp.watch('./src/*.html', browserSync.reload); gulp.watch('./src/js/**/*.js', browserSync.reload); }); // 構建最終輸出文件 gulp.task('build', function (callback) { runSequence('clean:dist', ['sass', 'useref', 'images', 'fonts'], callback); }); // gulp 默認執行任務 gulp.task('default', function (callback) { runSequence(['sass', 'browserSync', 'watch'], callback); });
2.在開發移動端頁面的時候,咱們須要兼容各類機型,iphone的機型相對來講比較少,可是android的機型倒是多種多樣,若是按照之前pc上開發頁面的經驗使用px來開發,確定會遇到各類兼容問題。雖然能夠用media query來適配,可是這種適配將是一個很是繁瑣的事情。那有沒有更好的解決辦法呢?固然是有的。在這裏推薦淘寶的可伸縮佈局方案lib-flexible
實現原理見: https://github.com/amfe/article/issues/17
須要注意的地方是: 在設置字體的時候須要根據dpr來調整字體大小(若是不設置會致使dpr高的手機由於縮放係數小而致使文字在手機上看起來很小)。以下代碼所示:javascript
[data-dpr="1"] .preloader,[data-dpr="1"] .swiper-slide { font-size: 18px; } [data-dpr="2"] .preloader,[data-dpr="2"] .swiper-slide { font-size: 36px; } [data-dpr="2.5"] .preloader,[data-dpr="2.5"] .swiper-slide { font-size: 45px; } [data-dpr="2.75"] .preloader,[data-dpr="2.75"] .swiper-slide { font-size: 49px; } [data-dpr="3"] .preloader,[data-dpr="3"] .swiper-slide { font-size: 64px; } [data-dpr="4"] .preloader,[data-dpr="4"] .swiper-slide { font-size: 72px; }
3.爲了更快的呈現頁面,頁面使用到的圖片第一時間並不加載,而是在預加載界面才加載圖片,固然同時也能夠加載js和其餘多媒體文件等。你們能夠在網上找到一些預加載的開源組件,或者本身寫一個預加載的組件。php
4.爲了減小http請求數,能夠把一些小的圖片合併成一張雪碧圖。默認spritesmith 生成的雪碧圖代碼是經過像素來定位的。可是咱們頁面使用的rem
。若是使用默認生成的雪碧圖代碼會致使圖片顯示並不完整。解決辦法是經過background-position 百分比來實現。具體實現原理參見:移動端適配之雪碧圖(sprite)背景圖片定位。
本身寫了一個sass方法來把spritesmith生成的sass代碼轉換爲background-position的實現。以下:css
//spritesmith 生成的sprite.sass,主要是須要獲取到sprite圖片中各圖片的大小,用來計算background-position的值。大概以下代碼所示: $cloud-b: (686px, 0px, -686px, 0px, 800px, 306px, 1486px, 1173px, '../img/sprite/sprite.png', 'cloud-b', ); // sass方法 $base: 72px; @function rem($size) { $remSize: $size / $base; @return #{$remSize}rem; } @mixin bgPostion($sprite){ $iconX:nth($sprite, 1); $spriteWidth:nth($sprite, 7); $iconWidth:nth($sprite, 5); $iconY:nth($sprite, 2); $spriteHeight:nth($sprite, 8); $iconHeight:nth($sprite, 6); $x:0; $y:0; @if $iconX != 0{ $x: ($iconX / ($spriteWidth - $iconWidth)) * 100%; } @if $iconY != 0{ $y: ($iconY / ($spriteHeight - $iconHeight)) * 100%; } background-position: ( $x $y ); } @mixin bg($sprite){ $sprite-width:nth($sprite, 7); $sprite-height:nth($sprite, 8); background: transparent; background-repeat: no-repeat; background-size: rem($sprite-width), rem($sprite-height); width: rem(nth($sprite, 5)); height: rem(nth($sprite, 6)); @include bgPostion($sprite); }
經過使用@include bg($cloud-b);
就能夠引入sprite圖片中相應的圖片了。html
注意點: 在默認生成的sprite圖片中各個小圖片之間是沒有間隔的。這致使使用上面的方法的時候在部分機型上會多顯示1像素旁邊圖片的邊框。解決辦法是在生成sprite圖片的時候參數設置padding值:java
gulp.task('sprite', function () { var spriteData = gulp.src('./src/img/sprite/**/*.png') .pipe(spritesmith({ imgName: 'sprite.png', cssName: 'sprite.scss', imgPath: '../img/sprite/sprite.png', cssFormat: 'scss', padding: 10 })); return spriteData.pipe(gulp.dest('./src/img/sprite/')) });
在使用幀動畫sprite圖的時候,能夠設置下圖片排列算法,好比說橫向排練,這樣在使用的時候也比較方便。algorithm: 'left-right',
android
5.在實現吹風的動畫時,具體請看報告第三頁,使用了svg來實現。主要是使用path的 stroke-dasharray 和stroke-dashoffset屬性。原理能夠參考帥氣的SVG路徑描邊動畫 (path animation) 實戰應用](https://segmentfault.com/a/1190000007811310)。
不過在實現的時候,咱們不僅僅須要風出現也須要風消失。實現的代碼以下:css3
.cls-wind{ // 省略其餘代碼 stroke-dasharray: 100px; stroke-dashoffset: 120px; animation: winds 2s ease infinite; } @keyframes winds{ from{ stroke-dashoffset: 120px; } 50%{ stroke-dashoffset: 0; } to{ stroke-dashoffset: -90px; } }
注意點: 在使用AI或者PS生成svg圖像的時候,生成的文件會有不少多餘的信息。能夠利用svgo 來處理多餘的信息,圖像的文件尺寸會減小不少。在這也提一下圖片壓縮,移動端流量是很寶貴的,圖片的尺寸在保證效果的狀況下越小越好,可是我在使用過程當中發現imagemin
的壓縮效果並非很是理想,雖然能夠壓縮一點,可是效果不明顯。後面使用tinypng 壓縮對比的時候,發現tinypng的壓縮效果很是好,通常都能壓縮個50%的大小,而且壓縮後的圖片在手機上的表現肉眼幾乎看不出來。因此,我的建議在正式發佈的時候,使用tinypng把你須要使用到的圖片都壓縮一遍。git
6.在使用css3動畫的時候,咱們應該儘可能避免瀏覽器的reflow,reflow會針對整個頁面進行重排,比較耗費性能。在實現報告中報告內容下拉的效果時,一開始使用的變換元素的height來實現。代碼大概以下:github
@keyframes conten-action{ from{ height:0; } to{ height:5rem; } }
可是這樣在一些低端的機型上表現不是很好。後面換成經過變換background-size 來實現,能夠明顯的感受到在那些低端的機型上動畫流暢了不少。代碼大概以下:web
@keyframes content-action{ from{ background-size: 100% 0%; opacity: 0; } 20%{ background-size: 100% 20%; opacity: 0; } to{ background-size: 100% 100%; opacity: 1; } }
固然css3的動畫性能優化還有不少其餘方面能夠探索。我這就只記錄我碰到的狀況了。
7.在報告最後一頁,會有一個火箭發射的效果。一開始想使用css3來實現,後面討論說使用css3工做量太大了,可使用視頻來播放這個動畫,如今已經有不少h5頁面是用視頻來實現的,說明視頻方案已是很成熟了。
咱們目前只支持微信端,這裏說明的狀況都是針對微信的狀況。
如今微信都已經支持了video的playsinline屬性,同時放開的playsinline的權限,好像在去年年末以前還須要向微信申請白名單才能夠,如今已經不須要了。playsinline可讓視頻內嵌在h5頁面中播放,這樣會讓用戶感受這個視頻就是h5的一部分,使用體驗上會好不少。我使用的video代碼以下:
<video class="video" id="video" x-webkit-airplay="allow" playsinline webkit-playsinline preload="auto" src="./video/rocket.mp4"></video>
在開始測試的時候發現,雖然視頻能夠內嵌播放了,可是在視頻上會出現一個全屏和一個小窗的按鈕。點擊全屏按鈕,視頻會全屏播放,播放完還會顯示廣告。。。點擊小窗按鈕,視頻會縮小成小窗。這兩個按鈕對於報告來講,就是多此一舉了。後面瞭解到這兩個按鈕是能夠隱藏的,可是須要向瀏覽器x5內核那邊申請白名單。申請後白名單後,按鈕就不會出現了
andriod的機器不支持autoplay,必定須要有交互(touch,click等)來能播放,因此在第一頁的時候當用戶touchstart的時候,調用下video.play();video.pause()
.同時,iphone不支持preload,在第一頁調用了video.play()
,會觸發視頻的下載,在最後須要播放的時候,視頻能夠順利的播放。
視頻初始化在各個手機上表現的形式並不同,可是又須要有一個表現一致的效果。解決辦法是,在尚未進入到最後一頁的時候,設置video的寬高都爲1px,等進入到最後一頁的時候,在把寬度設爲100%,高度設爲auto。同時把視頻的第一幀設爲最後一頁的背景圖,這樣每一個人看到的第一眼畫面都是同樣的。這裏須要注意一點,在設置背景圖的時候background-size
應該設置爲cover
,否則在播放視頻的時候,若是視頻的寬高比跟手機寬高比不同會致使第一幀跳動的感受,體驗上會打折扣。
在視頻播放完後,會有文字再顯示出來。 開始的作法是監聽video
的end
事件,可是這在iphone 上會出現屏幕黑一下,再出現文字。體驗上又會打折扣了。問題引發的緣由,應該是視頻播放完了,播放器的變成了黑色,就像在pc上播放完,播放器黑掉同樣。解決的辦法是: 設置一個定時器監聽video
的currentTime,當currentTime距離視頻播放的時候還差幾百毫秒的時候,顯示文字,隱藏視頻。大概的代碼以下:
var videoTimer = setInterval(function () { if(video[0].currentTime > 6.5){ if(!videoEnd){ $(".check").show(); $(".pub").show(); $(".p2").css({'opacity': 1}); $(".check").addClass('check-ani'); $(".pub").addClass('check-ani'); $(".dong").addClass('bounceInDown'); $(".wish").addClass('wish-ani'); videoEnd = 1; } } }, 200);
不過這須要在製做視頻的時候把這一段的時間留出來,同時也要考慮視頻結束時跟文字出來之間的銜接,這能夠跟設計師討論研究了。
難題: 在iphone上偶爾會出現,視頻不會播放。可是若是刷新下頁面視頻就能夠正常的播放了。 在用測試機來重現這種狀況的時候,又沒有遇到,很差定位到具體是啥緣由。 如今只有一個猜想的緣由:由於 video的play()方法即便是調用了,可是也不必定保證會播放。猜想多是視頻沒有緩衝好,在調用play() 方法後,視頻並無播放成功。 後面也是採起了定時去調用video的play()方法來嘗試解決這個問題,如今熱度也過了,也沒有收到視頻沒有播放的反饋。若是各位客官有碰到視頻沒有播放的狀況,麻煩留言通知聲。 在監聽視頻有沒有播放,是經過video 的timeupdate的事件來判斷,timeupdate事件在iOS和Android上表現一致。具體的代碼以下:
var videoPlayed = false; video.on("timeupdate", function () { videoPlayed = true; }); // 到第九頁時判斷 if(pageIndex === 9){ videoPlayed = false; videoPlayedTimer = setInterval(function () { if(!videoPlayed){ playVideo(); } }, 300); playVideo(); }
補充:
8.使用視頻的時候,開始設計師導出的視頻有1M多,這在移動端感受仍是有點太大了,何況視頻只有7s。 後來使用了ffmpeg來壓縮一下,視頻大小減小了不少。從最終的1.8M 減小到了330kb。同時在各個手機上的視頻清晰度變化肉眼是很難發現的。我使用的是ffmpeg默認的轉換參數,固然你們也能夠根據須要本身調整。