服務過美國總統競選的非傳統投票UI [解析及DEMO]


上篇文章和大家介紹了需求情況和難點分析,大家可以看這個鏈接了解詳細
 
 
 =================正文開始=====================================
 
 
這些天一直在忙,抽空把代碼完成了。和大家分享一下實現。
 
大家先在chorme上看一下DEMO吧,在線DEMO地址 http://codepen.io/arfeizhang/full/liIHa 
 (DEMO只是為了說明原理,所以沒做瀏覽器兼容,請大家在chrome上體驗下)
 
 DEMO看着還可以吧,我們開始分析啦~
 
這種非常規的UI,在底層還是由常規的元素組成,在實現上,需要前端開發者想辦法,創造(沒錯,是創造,在現在常規資源的基礎上進行組合創造)出非常規的效果。
 
接下來,我們切入正題。
 
看到效果圖后,我分析了一下,打算這樣搭元素結構。最外面一個div,作為這個ui的最外層,里面再來三個div,兩個用來放置左右直角梯形(里面再放圖片和文字元素),余下的一個做成中間的faceoff圖標。
 
html代碼結構是這個樣子。
 1 <div id="faceoff">
 2     <div id="person1" class="pic_wrap">
 3         <div class="pic">
 4          <div class="desc">          
 5           <div class="content">
 6  Raised in Bloomfield Hills, Michigan, by his parents George and Lenore Romney, Mitt Romney spent two and a half years in France as a Mormon missionary starting in 1966. In 1969 he married Ann Davies, with whom he has had five sons. By 1971, Romney had participated in the political campaigns of both of his parents. He earned a Bachelor of Arts at Brigham Young and in 1975.  7         </div>
 8           <div class="title">Mitt Romney</div>
 9         </div>
10       </div>
11     </div>
12 <div id="faceoffIcon">FACEOFF</div>
13     <div id="person2" class="pic_wrap">
14      <div class="pic">
15         <div class="desc">
16           <div class="title">Barack Obama</div>
17           <div class="content"> 
18  Born in Honolulu, Hawaii, Obama is a graduate of Columbia University and Harvard Law School, where he served as president of the Harvard Law Review. He was a community organizer in Chicago before earning his law degree. He worked as a civil rights attorney and taught constitutional law at the University of Chicago Law School from 1992 to 2004. 19                </div>
20         </div>
21       </div>
22     </div>
23 </div>

  

接着來解決直角梯形UI,我想着可以這樣實現:把一個矩形進行沿x軸歪斜(skew),這個矩形就會變成個棱形(如下圖),然后我們把左尖角或右尖角遮住,就變成直角梯形了(相當於切掉左/右角)。不過在過程中發現了一個問題:形狀達到我們要求了,但隨之而來的問題是,里面的圖像也扭曲了,就像下面這樣。
這個好辦,我們把圖像再扭回來就是了。來,反向扯一下。OK!現在正常了。
 
 
直角梯形的原理,如下圖所示:
 
 
 
補充一句,這種做法還可以做這種非常規ui
 
 
 
PS.還可以用webkit clip來實現非常規形狀,大家可以查下它的用法。
 
做好了形狀,接着來完成文字部分,這種非常規排版方式,adobe有過提議(CSS Shape),但目前CSS Shape只能在Webkit Nightly和Chrome Canary瀏覽器中實現,等以后等普及后,我們可以做出類似於這種效果。
 
 
因為瀏覽器支持度不夠,我們要實現非常規的UI,還是得用別的辦法。plusice同學提出,我們可以在文字中插入一些&nbsp;(空格)達到這個效果,這種方法可行,但難點是,需要找到插入點和應插入的空格數量。
 
我用另一種辦法達到了這個效果,給大家看三張圖,大家就能理解了:
 
 
 
 
上面最后一張圖,為了方便大家看,我把介紹內容給移了一下。大家應該看出來了吧,我是利用一些透明的占位元素(這里加了紅色邊框是為了使大家看得清楚),將介紹給擠成我們要的形狀。
 
這種做法需要解決的是,這些占位元素的寬度各是多少?這里我們借助程序來實現。
 
1 //依據角的鄰邊算對邊長度
2 function getWidth(height) { 3   return Math.tan(deg * Math.PI / 180) * height; 4 } 5 // 依據行數得到角的鄰邊長度,進而算得對邊長度
6 function getWidthByLineIndex(i) { 7   return getWidth(i * lineHeight); 8 }

 

這個程序的作用是,依據索引值生成一些依次遞增或遞減的span並把它加入到介紹div內。我們需要預定好角度值deg,這里我定義的是13度,和頁面上的直角梯形角度一致。
 
文本內容完成了,接下來做遮罩。使鼠標在圖片上面時,介紹內容滑下來。這個一般是用改變dom的屬性實現的,但不是本文的重點,我就偷個懶直接用css3 動畫來做了。
 
 1 #person1>.pic:hover>.desc {
 2  -webkit-animation: left-show 0.8s 0s normal forwards;
 3  -webkit-animation-timing-function: ease-in;
 4 }
 5 #person1>.pic>.desc {
 6  -webkit-animation: left-hide 0.8s 0s normal forwards;
 7  -webkit-animation-timing-function: ease-out;
 8 }
 9 #person2>.pic:hover>.desc {
10  -webkit-animation: right-show 0.8s 0s normal forwards;
11  -webkit-animation-timing-function: ease-in;
12 }
13 #person2>.pic>.desc {
14  -webkit-animation: right-hide 0.8s 0s normal forwards;
15  -webkit-animation-timing-function: ease-out;
16 }
17 @-webkit-keyframes left-show {
18  from { 19  margin-top: -440px;
20     }
21  to {
22  margin-top: 0px;
23     }
24 } 25 @-webkit-keyframes left-hide {
26  from { 27  margin-top: 0px;
28     }
29  to {
30  margin-top: -440px;
31     }
32 } 33 @-webkit-keyframes right-show {
34  from { 35  margin-top: 440px;
36     }
37  to {
38  margin-top: 0px;
39     }
40 } 41 @-webkit-keyframes right-hide {
42  from { 43  margin-top: 0px;
44     }
45  to {
46  margin-top: 440px;
47     }
48 }
hover滑動動畫

 

 恩,上下滑動功能正常,鼠標響應區域和文本內容也是直角梯形。好了,我們把它完成了!!!活動下手~~~~~~~ 等等,有個問題,被我們旋轉的左右部分div,斜邊出現了鋸齒,還是比較明顯的。
 
 
好吧,抱着追求完美的心態,我們來解決這個問題。將元素3d變換不僅可以開啟硬件加速,讓元素脫離文檔流,提升性能,還可以達到我們的目的-反鋸齒。但缺點是,字會有點模糊(因為它會把在上面的圖或文字等內容當成圖片紋理來貼圖),不過這個小瑕疵比鋸齒好得多。如果大家有別的方法完美消鋸齒,也請告訴我。
 
 
好,收攤。現在各位感覺到了,實現這個UI其實也不難,要用點巧即可。實現方法不止一種,我感覺我雖然實現了這個需求,但我相信還有別的更優雅的辦法。此文僅做拋磚引玉,大家如果有別的實現方法,和我分享下喲。 :)
所有代碼如下:
 1 <!DOCTYPE HTML>
 2 <html manifest="" lang="en-US">
 3 <head>
 4     <meta charset="UTF-8">   
 5         <title>Faceoff</title>
 6         <style type="text/css">
 7 div#faceoff {
 8  overflow: hidden;
 9  width: 710px;
 10 }
 11 .pic>.desc {
 12  background-color: rgba(0, 0, 0, 0.5);
 13  color: white;
 14 }
 15 .pic>.desc>.content {
 16  font-size: 22px;
 17  line-height: 26px;
 18  word-break: break-all;
 19 }
 20 .pic>.desc>.title {
 21  font-size: 30px;
 22  margin-bottom: 20px;
 23 }
 24 .pic_wrap {
 25  -webkit-transform: skewX(-13deg) translateZ(0);
 26  overflow: hidden;
 27  width: 353px;
 28  height: 480px;
 29  position: relative;
 30 }
 31 #person1 {
 32  left: -87px;
 33  float: left;
 34 }
 35 #person1>.pic {
 36  width: 461px;
 37  height: 480px;
 38  background: url("resources/1.jpg") no-repeat;
 39  background-position: -51px 0px;
 40  background-size: 620px 480px;
 41  -webkit-transform: skewX(13deg);
 42 }
 43 #person1>.pic>.desc {
 44  width: 312px;
 45  float: left;
 46  margin-left: 90px;
 47  margin-top: -440px;
 48 }
 49 #person1>.pic>.desc>.title {
 50  text-align: left;
 51  padding-left: 5px;
 52 }
 53 #person1>.pic>.desc>.content {
 54  padding: 2px;
 55  height: 440px;
 56 }
 57 #person2 {
 58  left: -57px;
 59 }
 60 #person2>.pic {
 61  width: 361px;
 62  height: 480px;
 63  background: url("resources/2.jpg") no-repeat;
 64  background-position: 20px -25px;
 65  background-size: 376px 540px;
 66  -webkit-transform: skewX(13deg);
 67  margin-left: -100px;
 68 }
 69 #person2>.pic>.desc {
 70  width: 320px;
 71  float: right;
 72 }
 73 #person2>.pic>.desc>.title {
 74  text-align: right;
 75  padding-right: 5px;
 76 }
 77 #person2>.pic>.desc>.content {
 78  padding-right: 2px;
 79  height: 440px;
 80 }
 81 .space {
 82     /* border: 1px solid red;*/
 83  height: 22px;
 84 }
 85 .space.left {
 86  float: left;
 87  clear: left;
 88 }
 89 .space.right {
 90  float: right;
 91  clear: right;
 92 }
 93 #faceoffIcon {
 94  width: 80px;
 95  height: 80px;
 96  position: absolute;
 97  background-color: red;
 98  border: 3px solid white;
 99  border-radius: 40px;
100  top: 194px;
101  left: 247px;
102  z-index: 2;
103  color: white;
104  line-height: 80px;
105  text-align: center;
106  font-weight: bold;
107 }
108 #faceoff:hover>#faceoffIcon {
109  display: none;
110 }
111 #person1>.pic:hover>.desc {
112  -webkit-animation: left-show 0.8s 0s normal forwards;
113  -webkit-animation-timing-function: ease-in;
114 }
115 #person1>.pic>.desc {
116  -webkit-animation: left-hide 0.8s 0s normal forwards;
117  -webkit-animation-timing-function: ease-out;
118 }
119 #person2>.pic:hover>.desc {
120  -webkit-animation: right-show 0.8s 0s normal forwards;
121  -webkit-animation-timing-function: ease-in;
122 }
123 #person2>.pic>.desc {
124  -webkit-animation: right-hide 0.8s 0s normal forwards;
125  -webkit-animation-timing-function: ease-out;
126 }
127 @-webkit-keyframes left-show {
128  from { 129  margin-top: -440px;
130     }
131  to {
132  margin-top: 0px;
133     }
134 } 135 @-webkit-keyframes left-hide {
136  from { 137  margin-top: 0px;
138     }
139  to {
140  margin-top: -440px;
141     }
142 } 143 @-webkit-keyframes right-show {
144  from { 145  margin-top: 440px;
146     }
147  to {
148  margin-top: 0px;
149     }
150 } 151 @-webkit-keyframes right-hide {
152  from { 153  margin-top: 0px;
154     }
155  to {
156  margin-top: 440px;
157     }
158 } 159 
160     </style>
161 </head>
162 <body>
163   <div id="faceoff">
164     <div id="person1" class="pic_wrap">
165         <div class="pic">
166          <div class="desc">          
167           <div class="content">
168  Raised in Bloomfield Hills, Michigan, by his parents George and Lenore Romney, Mitt Romney spent two and a half years in France as a Mormon missionary starting in 1966. In 1969 he married Ann Davies, with whom he has had five sons. By 1971, Romney had participated in the political campaigns of both of his parents. He earned a Bachelor of Arts at Brigham Young and in 1975. 169         </div>
170           <div class="title">Mitt Romney</div>
171         </div>
172       </div>
173     </div>
174 <div id="faceoffIcon">FACEOFF</div>
175     <div id="person2" class="pic_wrap">
176      <div class="pic">
177         <div class="desc">
178           <div class="title">Barack Obama</div>
179           <div class="content"> 
180  Born in Honolulu, Hawaii, Obama is a graduate of Columbia University and Harvard Law School, where he served as president of the Harvard Law Review. He was a community organizer in Chicago before earning his law degree. He worked as a civil rights attorney and taught constitutional law at the University of Chicago Law School from 1992 to 2004. 181                </div>
182         </div>
183       </div>
184     </div>
185 </div>
186 
187 <script type="text/javascript">
188 //角度為13度
189 var deg = 13, 190   //占位元素的高
191  lineHeight = 22, 192   //元素高
193  contentHeight = 460, 194   //占位元素個數(行數)
195  lineCount = Math.ceil(contentHeight / lineHeight), 196   //相鄰兩個占位元素的寬度偏移量
197  lineOffset = getWidth(lineHeight), 198   //最大占位容器寬度,右側的占位容器從大到小遞減,左側的占位元素從小到大遞增
199  lineMaxWidth = getWidth(contentHeight); 200 
201 //用占位容器來填充形狀
202 function SetShape(isRight) { 203   var oFrag = document.createDocumentFragment(); 204   if (isRight) { 205     for (var i = 0; i < lineCount; i++) { 206       var op = document.createElement("span"); 207  op.classList.add("space"); 208  op.classList.add("left"); 209       // 右側的占位容器從大到小遞減
210  op.style.width = (lineMaxWidth - i * lineOffset) + "px"; 211  oFrag.appendChild(op); 212  } 213  document.querySelector("#person2 .desc").insertBefore(oFrag, document.querySelector("#person2 .content")); 214  } else { 215     for (var i = 0; i < lineCount; i++) { 216       var op = document.createElement("span"); 217  op.classList.add("space"); 218  op.classList.add("right"); 219       // 左側的占位元素從小到大遞增
220  op.style.width = (i * lineOffset) + "px"; 221  oFrag.appendChild(op); 222  } 223  document.querySelector("#person1 .desc").insertBefore(oFrag, document.querySelector("#person1 .content")); 224  } 225 
226 } 227 //依據角的鄰邊算對邊長度
228 function getWidth(height) { 229   return Math.tan(deg * Math.PI / 180) * height; 230 } 231 // 依據行數得到角的鄰邊長度,進而算得對邊長度
232 function getWidthByLineIndex(i) { 233   return getWidth(i * lineHeight); 234 } 235 SetShape(false); 236 SetShape(true); 237 </script>
238     
239     </body>
240     </html>
faceoff全部代碼

素材兩張(尺寸已縮小,可右鍵下載源圖):

 

 

 

 本文是博主Arfei Zhang原創,歡迎轉載。轉載請注明轉自博客園,並附上本文鏈接http://www.cnblogs.com/arfeizhang/p/faceoffdemo.html,謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM