-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathchapter5.html
1890 lines (1554 loc) · 156 KB
/
chapter5.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!doctype html>
<html lang="zh_CN">
<head>
<meta charset="utf-8" />
<title>第 5 章 完善布局</title>
<meta name="author" content="Andor Chen" />
<link rel="stylesheet" href="assets/styles/style.css" />
<script type="text/javascript" src="http://cdn.staticfile.org/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript" src="assets/js/global.js"></script>
</head>
<body>
<div class="wrapper">
<div class="header">
<h1 class="logo"><a class="ir" href="http://railstutorial-china.org/rails4">Ruby on Rails 教程</a></h1>
<p class="subtitle">Ruby on Rails Tutorial 原书第 2 版(涵盖 Rails 4)</p>
</div>
<div class="content">
<div class="item chapter">
<h1 id="chapter-5"><span>第 5 章</span> 完善布局</h1>
<ol class="toc"> <li class="level-2">
<a href="#section-5-1">5.1 添加一些结构</a>
</li>
<li class="level-3">
<a href="#section-5-1-1">5.1.1 网站导航</a>
</li>
<li class="level-3">
<a href="#section-5-1-2">5.1.2 Bootstrap 和自定义的 CSS</a>
</li>
<li class="level-3">
<a href="#section-5-1-3">5.1.3 局部视图</a>
</li>
<li class="level-2">
<a href="#section-5-2">5.2 Sass 和 asset pipeline</a>
</li>
<li class="level-3">
<a href="#section-5-2-1">5.2.1 Asset pipeline</a>
</li>
<li class="level-3">
<a href="#section-5-2-2">5.2.2 句法强大的样式表</a>
</li>
<li class="level-2">
<a href="#section-5-3">5.3 布局中的链接</a>
</li>
<li class="level-3">
<a href="#section-5-3-1">5.3.1 路由测试</a>
</li>
<li class="level-3">
<a href="#section-5-3-2">5.3.2 Rails 路由</a>
</li>
<li class="level-3">
<a href="#section-5-3-3">5.3.3 具名路由</a>
</li>
<li class="level-3">
<a href="#section-5-3-4">5.3.4 简化 RSpec 测试代码</a>
</li>
<li class="level-2">
<a href="#section-5-4">5.4 用户注册:第一步</a>
</li>
<li class="level-3">
<a href="#section-5-4-1">5.4.1 Users 控制器</a>
</li>
<li class="level-3">
<a href="#section-5-4-2">5.4.2 “注册”页面的 URL 地址</a>
</li>
<li class="level-2">
<a href="#section-5-5">5.5 小结</a>
</li>
<li class="level-2">
<a href="#section-5-6">5.6 练习</a>
</li>
</ol>
<div class="main">
<p><a href="chapter4.html">第 4 章</a>对 Ruby 做了简单的介绍,我们讲解了如何在应用程序中引入样式表,不过,就像在 <a href="chapter4.html#section-4-3-4">4.3.4 节</a>中说过的,这个样式表现在还是空的。本章我们会做些修改,把 Bootstrap 框架引入应用程序中,然后再添加一些自定义的样式。<sup class="footnote" id="fnref-5-1"><a href="#fn-5-1" rel="footnote">1</a></sup> 我们还会把已经创建的页面(例如“首页”和“关于”页面)添加到布局中(<a href="chapter5.html#section-5-1">5.1 节</a>)。在这个过程中,我们会介绍局部视图(partial)、Rails 路由和 asset pipeline,还会介绍 Sass(<a href="chapter5.html#section-5-2">5.2 节</a>)。我们还会用最新的 RSpec 技术重构<a href="chapter3.html">第 3 章</a>中的测试。最后,我们还会向前迈出很重要的一步:允许用户在我们的网站中注册。</p>
<div class="figure" id="figure-5-1">
<img src="figures/home_page_mockup_bootstrap.png" alt="home page mockup bootstrap" />
<p class="caption"><span>图 5.1:</span>示例程序“首页”的构思图</p>
</div>
<h2 id='section-5-1'><span>5.1</span> 添加一些结构</h2>
<p>本书是关于 Web 开发而不是 Web 设计的,不过在一个看起来很垃圾的应用程序中开发会让人提不起劲,所以本书我们要向布局中添加一些结构,再加入一些 CSS 构建基本的样式。除了使用自定义的 CSS 之外,我们还会使用 <a href="http://twitter.github.com/bootstrap/">Bootstrap</a>,由 Twitter 开发的开源 Web 设计框架。我们还要按照一定的方式组织代码,即使用局部视图来保持布局文件的结构清晰,避免大量的代码混杂在布局文件中。</p>
<p>开发 Web 应用程序时,尽早的对用户界面有个统筹安排往往会对你有所帮助。在本书后续内容中,我会经常插入网页的构思图(mockup)(在 Web 领域经常称之为“线框图(wireframe)”),这是对应用程序最终效果的草图设计。<sup class="footnote" id="fnref-5-2"><a href="#fn-5-2" rel="footnote">2</a></sup>本章大部分内容都是在开发 <a href="chapter3.html#section-3-1">3.1 节</a>中介绍的静态页面,页面中包含一个网站 LOGO、导航条头部和网站底部。这些网页中最重要的一个是“首页”,它的构思图如图 5.1 所示。图 5.7 是最终实现的效果。你会发现二者之间的某些细节有所不同,例如,在最终实现的页面中我们加入了一个 Rails LOGO——这没什么关系,因为构思图没必要画出每个细节。</p>
<p>和之前一样,如果你使用 Git 做版本控制的话,现在最好创建一个新分支:</p>
<div class="codeblock"><div class="highlight type-shell"><pre><span class="gp">$ </span>git checkout -b filling-in-layout
</pre></div>
</div>
<h3 id='section-5-1-1'><span>5.1.1</span> 网站导航</h3>
<p>在示例程序中加入链接和样式的第一步,要修改布局文件 <code>application.html.erb</code>(上次使用是在代码 4.3 中),添加一些 HTML 结构。我们要添加一些区域,一些 CSS class,以及网站导航。布局文件的内容参见代码 5.1,对各部分代码的说明紧跟其后。如果你迫不及待的想看到结果,请查看图 5.2。(注意:结果(还)不是很让人满意。)</p>
<div class="codeblock has-caption" id="codeblock-5-1"><p class="caption"><span>代码 5.1:</span>添加一些结构后的网站布局文件</p><p class="file"><code>app/views/layouts/application.html.erb</code></p><div class="highlight type-erb"><pre><span class="cp"><!DOCTYPE html></span>
<span class="nt"><html></span>
<span class="nt"><head></span>
<span class="nt"><title></span><span class="cp"><%=</span> <span class="n">full_title</span><span class="p">(</span><span class="k">yield</span><span class="p">(</span><span class="ss">:title</span><span class="p">))</span> <span class="cp">%></span><span class="nt"></title></span>
<span class="cp"><%=</span> <span class="n">stylesheet_link_tag</span> <span class="s2">"application"</span><span class="p">,</span> <span class="ss">media: </span><span class="s2">"all"</span><span class="p">,</span>
<span class="s2">"data-turbolinks-track"</span> <span class="o">=></span> <span class="kp">true</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">javascript_include_tag</span> <span class="s2">"application"</span><span class="p">,</span> <span class="s2">"data-turbolinks-track"</span> <span class="o">=></span> <span class="kp">true</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">csrf_meta_tags</span> <span class="cp">%></span>
<span class="c"><!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]--></span>
<span class="nt"></head></span>
<span class="nt"><body></span>
<span class="nt"><header</span> <span class="na">class=</span><span class="s">"navbar navbar-fixed-top navbar-inverse"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"navbar-inner"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">></span>
<span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"sample app"</span><span class="p">,</span> <span class="s1">'#'</span><span class="p">,</span> <span class="ss">id: </span><span class="s2">"logo"</span> <span class="cp">%></span>
<span class="nt"><nav></span>
<span class="nt"><ul</span> <span class="na">class=</span><span class="s">"nav pull-right"</span><span class="nt">></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Home"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Help"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Sign in"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="nt"></ul></span>
<span class="nt"></nav></span>
<span class="nt"></div></span>
<span class="nt"></div></span>
<span class="nt"></header></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">></span>
<span class="cp"><%=</span> <span class="k">yield</span> <span class="cp">%></span>
<span class="nt"></div></span>
<span class="nt"></body></span>
<span class="nt"></html></span>
</pre></div>
</div>
<p>我们从上往下看一下代码 5.1 中新添加的元素。<a href="chapter3.html#section-3-3-2">3.3.2 节</a>简单的介绍过,Rails 4 默认会使用 HTML5(如 <code><!DOCTYPE html></code> 所示),因为 HTML5 标准还很新,有些浏览器(特别是较旧版本的 IE 浏览器)还没有完全支持,所以我们加载了一些 JavaScript 代码(称作“<a href="http://code.google.com/p/html5shim/">HTML5 shim</a>”)来解决这个问题:</p>
<div class="codeblock"><div class="highlight type-html"><pre><span class="c"><!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]--></span>
</pre></div>
</div>
<p>如下有点古怪的句法</p>
<div class="codeblock"><div class="highlight type-html"><pre><span class="c"><!--[if lt IE 9]>
</span></pre></div>
</div>
<p>只有当 IE 浏览器的版本小于 9 时(<code>if lt IE 9</code>)才会加载其中的代码。这个奇怪的 <code>[if lt IE 9]</code> 句法不是 Rails 提供的,其实它是 IE 浏览器为了解决兼容性问题而特别支持的<a href="http://en.wikipedia.org/wiki/Conditional_comment">条件注释</a>(conditional comment)。这就带来了一个好处,因为这说明我们只会在 IE9 以前的版本中加载 HTML5 shim,而 Firefox、Chrome 和 Safari 等其他浏览器则不会受到影响。</p>
<p>后面的区域是一个 <code>header</code>,包含网站的 LOGO(纯文本)、一些小区域(使用 <code>div</code> 标签)和一个导航列表元素:</p>
<div class="codeblock"><div class="highlight type-erb"><pre><span class="nt"><header</span> <span class="na">class=</span><span class="s">"navbar navbar-fixed-top navbar-inverse"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"navbar-inner"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">></span>
<span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"sample app"</span><span class="p">,</span> <span class="s1">'#'</span><span class="p">,</span> <span class="ss">id: </span><span class="s2">"logo"</span> <span class="cp">%></span>
<span class="nt"><nav></span>
<span class="nt"><ul</span> <span class="na">class=</span><span class="s">"nav pull-right"</span><span class="nt">></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Home"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Help"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Sign in"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="nt"></ul></span>
<span class="nt"></nav></span>
<span class="nt"></div></span>
<span class="nt"></div></span>
<span class="nt"></header></span>
</pre></div>
</div>
<p><code>header</code> 标签的意思是放在网页顶部的内容。我们为 <code>header</code> 标签指定了三个 CSS class<sup class="footnote" id="fnref-5-3"><a href="#fn-5-3" rel="footnote">3</a></sup>,<code>navbar</code>、<code>navbar-fixed-top</code> 和 <code>navbar-inverse</code>,用空格分开:</p>
<div class="codeblock"><div class="highlight type-html"><pre><span class="nt"><header</span> <span class="na">class=</span><span class="s">"navbar navbar-fixed-top navbar-inverse"</span><span class="nt">></span>
</pre></div>
</div>
<p>所有的 HTML 元素都可以指定 class 和 id,它们不仅是个标注,在 CSS 样式中也有用(<a href="chapter5.html#section-5-1-2">5.1.2 节</a>)。class 和 id 之间主要的区别是,class 可以在同一个网页中多次使用,而 id 只能使用一次。这里的三个 class 在 Bootstrap 框架中有特殊的意义,我们会在 <a href="chapter5.html#section-5-1-2">5.1.2 节</a>中安装并使用 Bootstrap。<code>header</code> 标签内是一些 <code>div</code> 标签:</p>
<div class="codeblock"><div class="highlight type-html"><pre><span class="nt"><div</span> <span class="na">class=</span><span class="s">"navbar-inner"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">></span>
</pre></div>
</div>
<p><code>div</code> 标签是常规的区域,除了把文档分成不同的部分之外,没有特殊的意义。在以前的 HTML 中,<code>div</code> 标签被用来划分网站中几乎所有的区域,但是 HTML5 增加了 <code>header</code>、<code>nav</code> 和 <code>section</code> 元素,用来划分大多数网站中都有用到的区域。本例中,每个 <code>div</code> 也都指定了一个 CSS class。和 <code>header</code> 标签的 class 一样,这些 class 在 Bootstrap 中也有特殊的意义。</p>
<p>在这些 <code>div</code> 之后,有一些 ERb 代码:</p>
<div class="codeblock"><div class="highlight type-erb"><pre><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"sample app"</span><span class="p">,</span> <span class="s1">'#'</span><span class="p">,</span> <span class="ss">id: </span><span class="s2">"logo"</span> <span class="cp">%></span>
<span class="nt"><nav></span>
<span class="nt"><ul</span> <span class="na">class=</span><span class="s">"nav pull-right"</span><span class="nt">></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Home"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Help"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Sign in"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="nt"></ul></span>
<span class="nt"></nav></span>
</pre></div>
</div>
<p>这里使用了 Rails 中的 <code>link_to</code> 帮助方法来创建链接(在 <a href="chapter3.html#section-3-3-2">3.3.2 节</a>中我们是直接创建 <code>a</code> 标签来实现的)。<code>link_to</code> 的第一个参数是链接文本,第二个参数是链接地址。在 <a href="chapter5.html#section-5-3-3">5.3.3 节</a>中我们会指定链接地址为设置好的路由,这里我们用的是 Web 设计中经常使用的占位符 <code>#</code>。第三个参数是可选的,为一个 Hash,本例使用这个参数为 LOGO 添加了一个 <code>logo</code> id。(其他三个链接没有使用这个 Hash 参数,没关系,因为这个参数是可选的。)Rails 帮助方法经常这样使用 Hash 参数,可以让我们仅使用 Rails 的帮助方法就能灵活的添加 HTML 属性。</p>
<p>第二个 <code>div</code> 中是个导航链接列表,使用无序列表标签 <code>ul</code>,以及列表项目标签 <code>li</code>:</p>
<div class="codeblock"><div class="highlight type-erb"><pre><span class="nt"><nav></span>
<span class="nt"><ul</span> <span class="na">class=</span><span class="s">"nav pull-right"</span><span class="nt">></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Home"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Help"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Sign in"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="nt"></ul></span>
<span class="nt"></nav></span>
</pre></div>
</div>
<p>上面代码中的 <code>nav</code> 标签以前是不需要的,它的目的是显示导航链接。<code>ul</code> 标签指定的 <code>nav</code> 和 <code>pull-right</code> class 在 Bootstrap 中有特殊的意义。 Rails 处理这个布局文件并执行其中的 ERb 代码后,生成的列表如下面的代码所示:</p>
<div class="codeblock"><div class="highlight type-erb"><pre><span class="nt"><nav></span>
<span class="nt"><ul</span> <span class="na">class=</span><span class="s">"nav pull-right"</span><span class="nt">></span>
<span class="nt"><li><a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">></span>Home<span class="nt"></a></li></span>
<span class="nt"><li><a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">></span>Help<span class="nt"></a></li></span>
<span class="nt"><li><a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">></span>Sign in<span class="nt"></a></li></span>
<span class="nt"></ul></span>
<span class="nt"></nav></span>
</pre></div>
</div>
<p>布局文件的最后一个 <code>div</code> 是主内容区域:</p>
<div class="codeblock"><div class="highlight type-erb"><pre><span class="nt"><div</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">></span>
<span class="cp"><%=</span> <span class="k">yield</span> <span class="cp">%></span>
<span class="nt"></div></span>
</pre></div>
</div>
<p>和之前一样,<code>container</code> class 在 Bootstrap 中有特殊的意义。<a href="chapter3.html#section-3-3-4">3.3.4 节</a>已经介绍过,<code>yield</code> 会把各页面中的内容插入网站的布局中。</p>
<p>除了网站的底部(在 <a href="chapter5.html#section-5-1-3">5.1.3 节</a>添加)之外,布局现在就完成了,访问一下“首页”就能看到结果了。为了利用后面添加的样式,我们要向 <code>home.html.erb</code> 视图中加入一些元素。(参见代码 5.2。)</p>
<div class="codeblock has-caption" id="codeblock-5-2"><p class="caption"><span>代码 5.2:</span>“首页”的代码,包含一个到注册页面的链接</p><p class="file"><code>app/views/static_pages/home.html.erb</code></p><div class="highlight type-erb"><pre><span class="nt"><div</span> <span class="na">class=</span><span class="s">"center hero-unit"</span><span class="nt">></span>
<span class="nt"><h1></span>Welcome to the Sample App<span class="nt"></h1></span>
<span class="nt"><h2></span>
This is the home page for the
<span class="nt"><a</span> <span class="na">href=</span><span class="s">"http://railstutorial.org/"</span><span class="nt">></span>Ruby on Rails Tutorial<span class="nt"></a></span>
sample application.
<span class="nt"></h2></span>
<span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Sign up now!"</span><span class="p">,</span> <span class="s1">'#'</span><span class="p">,</span> <span class="ss">class: </span><span class="s2">"btn btn-large btn-primary"</span> <span class="cp">%></span>
<span class="nt"></div></span>
<span class="cp"><%=</span> <span class="n">link_to</span> <span class="n">image_tag</span><span class="p">(</span><span class="s2">"rails.png"</span><span class="p">,</span> <span class="ss">alt: </span><span class="s2">"Rails"</span><span class="p">),</span> <span class="s1">'http://rubyonrails.org/'</span> <span class="cp">%></span>
</pre></div>
</div>
<p>上面代码中第一个 <code>link_to</code> 创建了一个占位链接,指向<a href="chapter7.html">第 7 章</a>中创建的用户注册页面</p>
<div class="codeblock"><div class="highlight type-erb"><pre><span class="nt"><a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"btn btn-large btn-primary"</span><span class="nt">></span>Sign up now!<span class="nt"></a></span>
</pre></div>
</div>
<p><code>div</code> 标签中的 <code>hero-unit</code> class 在 Bootstrap 中有特殊的意义,注册按钮的 <code>btn</code>、<code>btn-large</code> 和 <code>btn-primary</code> 也是一样。</p>
<div class="figure" id="figure-5-2">
<img src="figures/layout_no_logo_or_custom_css_bootstrap_rails_4.png" alt="layout no logo or custom css bootstrap rails 4" />
<p class="caption"><span>图 5.2:</span>没有定义 CSS 的“首页”(<a href="http://localhost:3000/static_pages/home">/static_pages/home</a>)</p>
</div>
<p>第二个 <code>link_to</code> 用到了 <code>image_tag</code> 帮助方法,第一个参数是图片的路径;第二个参数是可选的,一个 Hash,本例中这个 Hash 参数使用一个 Symbol 键设置了图片的 <code>alt</code> 属性。为了更好的理解,我们来看一下生成的 HTML:<sup class="footnote" id="fnref-5-4"><a href="#fn-5-4" rel="footnote">4</a></sup></p>
<div class="codeblock"><div class="highlight type-html"><pre><span class="nt"><img</span> <span class="na">alt=</span><span class="s">"Rails"</span> <span class="na">src=</span><span class="s">"/assets/rails.png"</span> <span class="nt">/></span>
</pre></div>
</div>
<p>(注意,<code>src</code> 中并没有包含 <code>images</code>,Rails 会自动关联 <code>images</code> 文件夹中对应的图片。把静态资源文件放在 <code>assets</code> 文件夹中可以加快网页响应时间。)<code>alt</code> 属性的内容会在图片无法加载时显示,也会在针对视觉障碍人士的屏幕阅读器中显示。人们有时懒得加上 <code>alt</code> 属性,可是在 HTML 标准中却是必须的。幸运的是,Rails 默认会加上 <code>alt</code> 标签,如果你没有在调用 <code>image_tag</code> 时指定的话,Rails 就会使用图片的文件名(不包括扩展名)。本例中,我们自己设定了 <code>alt</code> 文本,显示一个首字母大写的“Rails”。</p>
<p>在 Rails 之前的版本中,每个 Rails 应用程序中都有 <code>rails.png</code> 这个图片,但在最新版中这个图片不会在执行 <code>rails new</code> 命令时生成,所以要手动从 Ruby on Rails 官网下载,地址为 <a href="http://rubyonrails.org/images/rails.png">http://rubyonrails.org/images/rails.png</a>,保存到 <code>app/assets/images/</code> 文件夹中。(或许还要新建这个文件夹,可以使用 <code>mkdir</code> 命令或者图形化文件管理工具。)因为在代码 5.2 中我们使用了 <code>image_tag</code> 帮助方法,所以 Rails 会通过 Asset Pipeline(参见 <a href="chapter5.html#section-5-2">5.2 节</a>)自动在这个文件夹中寻找所需的图片。</p>
<p>现在我们终于可以看到劳动的果实了(如图 5.2)。你可能会说,这并不很美观啊。或许吧。不过也可以小小的高兴一下,我们已经为 HTML 结构指定了合适的 class,可以用来添加 CSS。</p>
<h3 id='section-5-1-2'><span>5.1.2</span> Bootstrap 和自定义的 CSS</h3>
<p>在 <a href="chapter5.html#section-5-1-1">5.1.1 节</a>我们为很多 HTML 元素指定了 CSS class,这样我们就可以使用 CSS 灵活的构建布局了。<a href="chapter5.html#section-5-1-1">5.1.1 节</a>中已经说过,很多 class 在 Bootstrap 中都有特殊的意义。Bootstrap 是 Twitter 开发的框架,可以方便的把精美的 Web 设计和用户界面元素添加到使用 HTML5 开发的应用程序中。本节,我们会结合 Bootstrap 和一些自定义的 CSS 为示例程序添加样式。</p>
<p>首先要安装 Bootstrap,在 Rails 程序中可以使用 bootstrap-sass 这个 gem,参见代码 5.3。Bootstrap 框架本身使用 LESS 来动态的生成样式表,而 Rails 的 asset pipeline 默认支持的是(非常类似的)Sass,bootstrap-sass 会将 LESS 转换成 Sass 格式,而且 Bootstrap 中必要的文件都可以在当前的应用程序中使用。<sup class="footnote" id="fnref-5-5"><a href="#fn-5-5" rel="footnote">5</a></sup></p>
<div class="codeblock has-caption" id="codeblock-5-3"><p class="caption"><span>代码 5.3:</span>把 bootstrap-sass 加入 <code>Gemfile</code></p><div class="highlight type-ruby"><pre><span class="n">source</span> <span class="s1">'https://rubygems.org'</span>
<span class="n">ruby</span> <span class="s1">'2.0.0'</span>
<span class="n">gem</span> <span class="s1">'rails'</span><span class="p">,</span> <span class="s1">'4.0.4'</span>
<span class="n">gem</span> <span class="s1">'bootstrap-sass'</span><span class="p">,</span> <span class="s1">'2.3.2.0'</span>
<span class="p">.</span>
<span class="nf">.</span>
<span class="o">.</span>
</pre></div>
</div>
<p>像往常一样,运行 <code>bundle install</code> 安装 Bootstrap:</p>
<div class="codeblock"><div class="highlight type-shell"><pre><span class="gp">$ </span>bundle install
</pre></div>
</div>
<p>然后重启 Web 服务器,改动才能在应用程序中生效。(在大多数系统中可以使用 Ctrl-C 结束服务器,然后再执行 <code>rails server</code> 命令。)最后,对 Rails 4 来说,我们还要在 <code>config/application.rb</code> 中添加一行代码,让 <code>bootstrap-sass</code> 这个 gem 和 Asset Pipeline 兼容,如代码 5.4 所示。</p>
<div class="codeblock has-caption" id="codeblock-5-4"><p class="caption"><span>代码 5.4:</span>添加一行代码,兼容 Asset Pipeline</p><p class="file"><code>config/application.rb</code></p><div class="highlight type-ruby"><pre><span class="nb">require</span> <span class="no">File</span><span class="p">.</span><span class="nf">expand_path</span><span class="p">(</span><span class="s1">'../boot'</span><span class="p">,</span> <span class="kp">__FILE__</span><span class="p">)</span>
<span class="p">.</span>
<span class="nf">.</span>
<span class="p">.</span>
<span class="nf">module</span> <span class="no">SampleApp</span>
<span class="k">class</span> <span class="nc">Application</span> <span class="o"><</span> <span class="no">Rails</span><span class="o">::</span><span class="no">Application</span>
<span class="p">.</span>
<span class="nf">.</span>
<span class="p">.</span>
<span class="nf">config</span><span class="p">.</span><span class="nf">assets</span><span class="p">.</span><span class="nf">precompile</span> <span class="o">+=</span> <span class="sx">%w(*.png *.jpg *.jpeg *.gif)</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
</div>
<p>要向应用程序中添加自定义的 CSS,首先要创建一个 CSS 文件:</p>
<div class="codeblock"><div class="highlight type-plaintext"><pre>app/assets/stylesheets/custom.css.scss
</pre></div>
</div>
<p>文件存放的目录和文件名都很重要。其中目录</p>
<div class="codeblock"><div class="highlight type-plaintext"><pre>app/assets/stylesheets
</pre></div>
</div>
<div class="figure" id="figure-5-3">
<img src="figures/sample_app_only_bootstrap_4_0.png" alt="sample app only bootstrap 40" />
<p class="caption"><span>图 5.3:</span>使用 Bootstrap CSS 后的示例程序</p>
</div>
<p>是 asset pipeline 的一部分(<a href="chapter5.html#section-5-2">5.2 节</a>),这个目录中的所有样式表都会自动的包含在网站的 <code>application.css</code> 中。<code>custom.css.scss</code> 文件的第一个扩展名是 <code>.css</code>,说明这是个 CSS 文件;第二个扩展名是 <code>.scss</code>,说明这是个“Sassy CSS”文件。asset pipeline 会使用 Sass 处理这个文件。(在 <a href="chapter5.html#section-5-2-2">5.2.2 节</a>中才会使用 Sass,有了它 bootstrap-sass 才能运作。)</p>
<p>在自定义 CSS 文件中,我们可以使用 <code>@import</code> 引入 Bootstrap,如代码 5.5 所示。</p>
<div class="codeblock has-caption" id="codeblock-5-5"><p class="caption"><span>代码 5.5:</span>引入 Bootstrap</p><p class="file"><code>app/assets/stylesheets/custom.css.scss</code></p><div class="highlight type-scss"><pre><span class="k">@import</span> <span class="s2">"bootstrap"</span><span class="p">;</span>
</pre></div>
</div>
<p>这行代码会引入整个 Bootstrap CSS 框架,结果如图 5.3 所示。(或许你要通过 Ctrl-C 来重启服务器。还有一点要注意,截图中使用的是 Bootstrap 2.0,而本教程用的是 Bootstrap 2.3,所以外观可能有所不同,不过无需过分担心。)可以看到,文本的位置还不是很合适,LOGO 也没有任何样式,不过颜色搭配和注册按钮看起来还不错。</p>
<p>下面我们要加入一些整站都会用到的 CSS,用来样式化网站布局和各单独页面,如代码 5.6 所示。代码 5.6 中定义了很多样式规则。为了说明 CSS 规则的作用,我们经常会加入一些 CSS 注释,放在 <code>/*...*/</code> 之中。代码 5.6 的 CSS 加载后的效果如图 5.4 所示。</p>
<div class="figure" id="figure-5-4">
<img src="figures/sample_app_universal_4_0.png" alt="sample app universal 40" />
<p class="caption"><span>图 5.4:</span>添加一些空白和其他的全局性样式</p>
</div>
<div class="codeblock has-caption" id="codeblock-5-6"><p class="caption"><span>代码 5.6:</span>添加全站使用的 CSS</p><p class="file"><code>app/assets/stylesheets/custom.css.scss</code></p><div class="highlight type-scss"><pre><span class="k">@import</span> <span class="s2">"bootstrap"</span><span class="p">;</span>
<span class="cm">/* universal */</span>
<span class="nt">html</span> <span class="p">{</span>
<span class="nl">overflow-y</span><span class="p">:</span> <span class="nb">scroll</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">body</span> <span class="p">{</span>
<span class="nl">padding-top</span><span class="p">:</span> <span class="m">60px</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">section</span> <span class="p">{</span>
<span class="nl">overflow</span><span class="p">:</span> <span class="nb">auto</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">textarea</span> <span class="p">{</span>
<span class="nl">resize</span><span class="p">:</span> <span class="n">vertical</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.center</span> <span class="p">{</span>
<span class="nl">text-align</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.center</span> <span class="nt">h1</span> <span class="p">{</span>
<span class="nl">margin-bottom</span><span class="p">:</span> <span class="m">10px</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>注意代码 5.6 中的 CSS 格式是很统一的。一般来说,CSS 规则是通过 class、id、HTML 标签或者三者结合在一起来定义的,后面会跟着一些样式声明。例如:</p>
<div class="codeblock"><div class="highlight type-css"><pre><span class="nt">body</span> <span class="p">{</span>
<span class="nl">padding-top</span><span class="p">:</span> <span class="m">60px</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>把页面的上内边距设为 60 像素。我们在 <code>header</code> 标签上指定了 <code>navbar-fixed-top</code> class,Bootstrap 就把这个导航条固定在页面的顶部。所以页面的上内边距会把主内容区和导航条隔开一段距离。(导航条的颜色在 Bootstrap 2.0 和 2.1 之间是不一样的,所以我们要加入 <code>navbar-inverse</code> class,把亮色变暗。)下面的 CSS 规则:</p>
<div class="codeblock"><div class="highlight type-css"><pre><span class="nc">.center</span> <span class="p">{</span>
<span class="nl">text-align</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>把 <code>.center</code> class 的样式定义为 <code>text-align: center;</code>。<code>.center</code> 中的点号说明这个规则是样式化一个 class。(我们会在代码 5.8 中看到,<code>#</code> 是样式化一个 id。)这个规则的意思是,任何 class 为 <code>.center</code> 的标签(例如 <code>div</code>),其中包含的内容都会在页面中居中显示。(代码 5.2 中有用到这个 class。)</p>
<p>虽然 Bootstrap 中包含了很精美的文字排版样式,我们还是要为网站添加一些自定义的规则,如代码 5.7 所示。(并不是所有的样式都会应用于“首页”,但所有规则都会在网站中的某个地方用到。)代码 5.7 的效果如图 5.5 所示。</p>
<div class="figure" id="figure-5-5">
<img src="figures/sample_app_typography_4_0.png" alt="sample app typography 40" />
<p class="caption"><span>图 5.5:</span>添加了一些文字排版样式</p>
</div>
<div class="codeblock has-caption" id="codeblock-5-7"><p class="caption"><span>代码 5.7:</span>添加一些精美的文字排版样式</p><p class="file"><code>app/assets/stylesheets/custom.css.scss</code></p><div class="highlight type-scss"><pre><span class="k">@import</span> <span class="s2">"bootstrap"</span><span class="p">;</span>
<span class="nc">.</span>
<span class="nc">.</span>
<span class="nc">.</span>
<span class="o">/*</span> <span class="nt">typography</span> <span class="o">*/</span>
<span class="nt">h1</span><span class="o">,</span> <span class="nt">h2</span><span class="o">,</span> <span class="nt">h3</span><span class="o">,</span> <span class="nt">h4</span><span class="o">,</span> <span class="nt">h5</span><span class="o">,</span> <span class="nt">h6</span> <span class="p">{</span>
<span class="nl">line-height</span><span class="p">:</span> <span class="m">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">h1</span> <span class="p">{</span>
<span class="nl">font-size</span><span class="p">:</span> <span class="m">3em</span><span class="p">;</span>
<span class="nl">letter-spacing</span><span class="p">:</span> <span class="m">-2px</span><span class="p">;</span>
<span class="nl">margin-bottom</span><span class="p">:</span> <span class="m">30px</span><span class="p">;</span>
<span class="nl">text-align</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">h2</span> <span class="p">{</span>
<span class="nl">font-size</span><span class="p">:</span> <span class="m">1</span><span class="mi">.2em</span><span class="p">;</span>
<span class="nl">letter-spacing</span><span class="p">:</span> <span class="m">-1px</span><span class="p">;</span>
<span class="nl">margin-bottom</span><span class="p">:</span> <span class="m">30px</span><span class="p">;</span>
<span class="nl">text-align</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
<span class="nl">font-weight</span><span class="p">:</span> <span class="nb">normal</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="mh">#999</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">p</span> <span class="p">{</span>
<span class="nl">font-size</span><span class="p">:</span> <span class="m">1</span><span class="mi">.1em</span><span class="p">;</span>
<span class="nl">line-height</span><span class="p">:</span> <span class="m">1</span><span class="mi">.7em</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>最后,我们还要为只包含文本“sample app”的网站 LOGO 添加一些样式。代码 5.8 中的 CSS 样式会把文字变成全大写字母,还修改了文字大小、颜色和位置。(我们使用的是 id,因为我们希望 LOGO 在页面中只出现一次,不过你也可以使用 class。)</p>
<div class="figure" id="figure-5-6">
<img src="figures/sample_app_logo_4_0.png" alt="sample app logo 40" />
<p class="caption"><span>图 5.6:</span>样式化 LOGO 后的示例程序</p>
</div>
<div class="codeblock has-caption" id="codeblock-5-8"><p class="caption"><span>代码 5.8:</span>添加网站 LOGO 的样式</p><p class="file"><code>app/assets/stylesheets/custom.css.scss</code></p><div class="highlight type-scss"><pre><span class="k">@import</span> <span class="s2">"bootstrap"</span><span class="p">;</span>
<span class="nc">.</span>
<span class="nc">.</span>
<span class="nc">.</span>
<span class="o">/*</span> <span class="nt">header</span> <span class="o">*/</span>
<span class="nn">#logo</span> <span class="p">{</span>
<span class="nl">float</span><span class="p">:</span> <span class="nb">left</span><span class="p">;</span>
<span class="nl">margin-right</span><span class="p">:</span> <span class="m">10px</span><span class="p">;</span>
<span class="nl">font-size</span><span class="p">:</span> <span class="m">1</span><span class="mi">.7em</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="mh">#fff</span><span class="p">;</span>
<span class="nl">text-transform</span><span class="p">:</span> <span class="nb">uppercase</span><span class="p">;</span>
<span class="nl">letter-spacing</span><span class="p">:</span> <span class="m">-1px</span><span class="p">;</span>
<span class="nl">padding-top</span><span class="p">:</span> <span class="m">9px</span><span class="p">;</span>
<span class="nl">font-weight</span><span class="p">:</span> <span class="nb">bold</span><span class="p">;</span>
<span class="nl">line-height</span><span class="p">:</span> <span class="m">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="nn">#logo</span><span class="nd">:hover</span> <span class="p">{</span>
<span class="nl">color</span><span class="p">:</span> <span class="mh">#fff</span><span class="p">;</span>
<span class="nl">text-decoration</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>其中 <code>color: #fff;</code> 会把 LOGO 文字的颜色变成白色。HTML 中的颜色代码是由 3 个 16 进制数组成的,分别代表了三原色中的红、绿、蓝。<code>#ffffff</code> 是 3 种颜色都为最大值的情况,代表了纯白色。<code>#fff</code> 是 <code>#ffffff</code> 的简写形式。CSS 标准中为很多常用的 HTML 颜色定义了别名,例如 <code>white</code> 代表的是 <code>#fff</code>。代码 5.8 中的样式效果如图 5.6 所示。</p>
<h3 id='section-5-1-3'><span>5.1.3</span> 局部视图</h3>
<p>虽然代码 5.1 中的布局达到了目的,但它的内容看起来有点混乱。HTML shim 就占用了三行,而且使用了只针对 IE 的奇怪句法,所以如果能把它打包放在一个单独的地方就好了。头部的 HTML 自成一个逻辑单元,所以也可以把这部分打包放在某个地方。在 Rails 中我们可以使用局部视图来实现这种想法。先来看一下定义了局部视图之后的布局文件(参见代码 5.9)。</p>
<div class="codeblock has-caption" id="codeblock-5-9"><p class="caption"><span>代码 5.9:</span>定义了 HTML shim 和头部局部视图之后的网站布局</p><p class="file"><code>app/views/layouts/application.html.erb</code></p><div class="highlight type-erb"><pre><span class="cp"><!DOCTYPE html></span>
<span class="nt"><html></span>
<span class="nt"><head></span>
<span class="nt"><title></span><span class="cp"><%=</span> <span class="n">full_title</span><span class="p">(</span><span class="k">yield</span><span class="p">(</span><span class="ss">:title</span><span class="p">))</span> <span class="cp">%></span><span class="nt"></title></span>
<span class="cp"><%=</span> <span class="n">stylesheet_link_tag</span> <span class="s2">"application"</span><span class="p">,</span> <span class="ss">media: </span><span class="s2">"all"</span><span class="p">,</span>
<span class="s2">"data-turbolinks-track"</span> <span class="o">=></span> <span class="kp">true</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">javascript_include_tag</span> <span class="s2">"application"</span><span class="p">,</span> <span class="s2">"data-turbolinks-track"</span> <span class="o">=></span> <span class="kp">true</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">csrf_meta_tags</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">render</span> <span class="s1">'layouts/shim'</span> <span class="cp">%></span>
<span class="nt"></head></span>
<span class="nt"><body></span>
<span class="cp"><%=</span> <span class="n">render</span> <span class="s1">'layouts/header'</span> <span class="cp">%></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">></span>
<span class="cp"><%=</span> <span class="k">yield</span> <span class="cp">%></span>
<span class="nt"></div></span>
<span class="nt"></body></span>
<span class="nt"></html></span>
</pre></div>
</div>
<p>代码 5.9 中,我们把加载 HTML shim 的那几行代码换成了对 Rails 帮助函数 <code>render</code> 的调用:</p>
<div class="codeblock"><div class="highlight type-erb"><pre><span class="cp"><%=</span> <span class="n">render</span> <span class="s1">'layouts/shim'</span> <span class="cp">%></span>
</pre></div>
</div>
<p>这行代码会寻找一个名为 <code>app/views/layouts/_shim.html.erb</code> 的文件,执行文件中的代码,然后把结果插入视图。<sup class="footnote" id="fnref-5-6"><a href="#fn-5-6" rel="footnote">6</a></sup>(回顾一下,执行 Ruby 表达式并将结果插入模板中要使用 <code><%=...%></code>。)注意文件名 <code>_shim.html.erb</code> 的开头是个下划线,这个下划线是局部视图的命名约定,可以在目录中快速定位所有的局部视图。</p>
<p>当然,若要局部视图起作用,我们要写入相应的内容。本例中的 HTML shim 局部视图只包含三行代码,如代码 5.10 所示。</p>
<div class="codeblock has-caption" id="codeblock-5-10"><p class="caption"><span>代码 5.10:</span>HTML shim 局部视图</p><p class="file"><code>app/views/layouts/_shim.html.erb</code></p><div class="highlight type-erb"><pre><span class="c"><!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]--></span>
</pre></div>
</div>
<p>类似的,我们可以把头部的内容移入局部视图,如代码 5.11 所示,然后再次调用 <code>render</code> 把这个局部视图插入布局中。</p>
<div class="codeblock has-caption" id="codeblock-5-11"><p class="caption"><span>代码 5.11:</span>网站头部的局部视图</p><p class="file"><code>app/views/layouts/_header.html.erb</code></p><div class="highlight type-erb"><pre><span class="nt"><header</span> <span class="na">class=</span><span class="s">"navbar navbar-fixed-top navbar-inverse"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"navbar-inner"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">></span>
<span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"sample app"</span><span class="p">,</span> <span class="s1">'#'</span><span class="p">,</span> <span class="ss">id: </span><span class="s2">"logo"</span> <span class="cp">%></span>
<span class="nt"><nav></span>
<span class="nt"><ul</span> <span class="na">class=</span><span class="s">"nav pull-right"</span><span class="nt">></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Home"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Help"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Sign in"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="nt"></ul></span>
<span class="nt"></nav></span>
<span class="nt"></div></span>
<span class="nt"></div></span>
<span class="nt"></header></span>
</pre></div>
</div>
<p>现在我们已经知道怎么创建局部视图了,让我们来加入和头部对应的网站底部吧。你或许已经猜到了,我们会把这个局部视图命名为 <code>_footer.html.erb</code>,放在布局目录中(参见代码 5.12)。<sup class="footnote" id="fnref-5-7"><a href="#fn-5-7" rel="footnote">7</a></sup></p>
<div class="codeblock has-caption" id="codeblock-5-12"><p class="caption"><span>代码 5.12:</span>网站底部的局部视图</p><p class="file"><code>app/views/layouts/_footer.html.erb</code></p><div class="highlight type-erb"><pre><span class="nt"><footer</span> <span class="na">class=</span><span class="s">"footer"</span><span class="nt">></span>
<span class="nt"><small></span>
<span class="nt"><a</span> <span class="na">href=</span><span class="s">"http://railstutorial.org/"</span><span class="nt">></span>Rails Tutorial<span class="nt"></a></span>
by Michael Hartl
<span class="nt"></small></span>
<span class="nt"><nav></span>
<span class="nt"><ul></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"About"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Contact"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="nt"><li><a</span> <span class="na">href=</span><span class="s">"http://news.railstutorial.org/"</span><span class="nt">></span>News<span class="nt"></a></li></span>
<span class="nt"></ul></span>
<span class="nt"></nav></span>
<span class="nt"></footer></span>
</pre></div>
</div>
<p>和头部类似,在底部我们使用 <code>link_to</code> 创建到“关于”页面和“联系”页面的链接,地址暂时使用占位符 <code>#</code>。(和 <code>header</code> 一样,<code>footer</code> 标签也是 HTML5 新增加的。)</p>
<p>按照 HTML shim 和头部局部视图采用的方式,我们也可以在布局视图中渲染底部局部视图。(参见代码 5.13。)</p>
<div class="codeblock has-caption" id="codeblock-5-13"><p class="caption"><span>代码 5.13:</span>网站的布局,包含底部局部视图</p><p class="file"><code>app/views/layouts/application.html.erb</code></p><div class="highlight type-erb"><pre><span class="cp"><!DOCTYPE html></span>
<span class="nt"><html></span>
<span class="nt"><head></span>
<span class="nt"><title></span><span class="cp"><%=</span> <span class="n">full_title</span><span class="p">(</span><span class="k">yield</span><span class="p">(</span><span class="ss">:title</span><span class="p">))</span> <span class="cp">%></span><span class="nt"></title></span>
<span class="cp"><%=</span> <span class="n">stylesheet_link_tag</span> <span class="s2">"application"</span><span class="p">,</span> <span class="ss">media: </span><span class="s2">"all"</span><span class="p">,</span>
<span class="s2">"data-turbolinks-track"</span> <span class="o">=></span> <span class="kp">true</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">javascript_include_tag</span> <span class="s2">"application"</span><span class="p">,</span> <span class="s2">"data-turbolinks-track"</span> <span class="o">=></span> <span class="kp">true</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">csrf_meta_tags</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">render</span> <span class="s1">'layouts/shim'</span> <span class="cp">%></span>
<span class="nt"></head></span>
<span class="nt"><body></span>
<span class="cp"><%=</span> <span class="n">render</span> <span class="s1">'layouts/header'</span> <span class="cp">%></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">></span>
<span class="cp"><%=</span> <span class="k">yield</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">render</span> <span class="s1">'layouts/footer'</span> <span class="cp">%></span>
<span class="nt"></div></span>
<span class="nt"></body></span>
<span class="nt"></html></span>
</pre></div>
</div>
<p>当然,如果没有样式的话,底部还是很丑的(样式参见代码 5.14)。添加样式后的效果如图 5.7 所示。</p>
<div class="codeblock has-caption" id="codeblock-5-14"><p class="caption"><span>代码 5.14:</span>添加底部所需的 CSS</p><p class="file"><code>app/assets/stylesheets/custom.css.scss</code></p><div class="highlight type-scss"><pre><span class="nc">.</span>
<span class="nc">.</span>
<span class="nc">.</span>
<span class="o">/*</span> <span class="nt">footer</span> <span class="o">*/</span>
<span class="nt">footer</span> <span class="p">{</span>
<span class="nl">margin-top</span><span class="p">:</span> <span class="m">45px</span><span class="p">;</span>
<span class="nl">padding-top</span><span class="p">:</span> <span class="m">5px</span><span class="p">;</span>
<span class="nl">border-top</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="mh">#eaeaea</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="mh">#999</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">footer</span> <span class="nt">a</span> <span class="p">{</span>
<span class="nl">color</span><span class="p">:</span> <span class="mh">#555</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">footer</span> <span class="nt">a</span><span class="nd">:hover</span> <span class="p">{</span>
<span class="nl">color</span><span class="p">:</span> <span class="mh">#222</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">footer</span> <span class="nt">small</span> <span class="p">{</span>
<span class="nl">float</span><span class="p">:</span> <span class="nb">left</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">footer</span> <span class="nt">ul</span> <span class="p">{</span>
<span class="nl">float</span><span class="p">:</span> <span class="nb">right</span><span class="p">;</span>
<span class="nl">list-style</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">footer</span> <span class="nt">ul</span> <span class="nt">li</span> <span class="p">{</span>
<span class="nl">float</span><span class="p">:</span> <span class="nb">left</span><span class="p">;</span>
<span class="nl">margin-left</span><span class="p">:</span> <span class="m">10px</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<h2 id='section-5-2'><span>5.2</span> Sass 和 asset pipeline</h2>
<p>在较新版本的 Rails 中,最大的变化是增加了 asset pipeline,这个功能可以明显提高如 CSS、JavaScript和图片等静态资源文件(asset)的生成效率,降低管理成本。本节我们会概览一下 asset pipeline,然后再介绍如何使用 Sass 这个生成 CSS 很强大的工具,Sass 现在是 asset pipeline 默认的一部分。</p>
<h3 id='section-5-2-1'><span>5.2.1</span> Asset pipeline</h3>
<p>Asset pipeline 对 Rails做了很多改动,但对 Rails 开发者来说只有三个特性需要了解:资源目录,清单文件(manifest file),还有预处理器引擎(preprocessor engine)。<sup class="footnote" id="fnref-5-8"><a href="#fn-5-8" rel="footnote">8</a></sup>我们会一个一个的介绍。</p>
<div class="figure" id="figure-5-7">
<img src="figures/site_with_footer_bootstrap_4_0.png" alt="site with footer bootstrap 40" />
<p class="caption"><span>图 5.7:</span>添加底部后的“首页”(<a href="http://localhost:3000/static_pages/home">/static_pages/home</a>)</p>
</div>
<h4 id='section-5-2-1-1'><span></span>资源目录</h4>
<p>在 Rails 3.0 之前(包括 3.0),静态文件分别放在如下的 <code>public/</code> 目录中:</p>
<ul>
<li><code>public/stylesheets</code></li>
<li><code>public/javascripts</code></li>
<li><code>public/images</code></li>
</ul>
<p>这些文件夹中的文件通过请求 http://example.com/stylesheets 等地址直接发送给浏览器。(Rails 3.0 之后的版本也可以这么做。)</p>
<p>从 Rails 3.1 开始到最新的 Rails 4,静态文件可以存放在三个标准的目录中,各有各的用途:</p>
<ul>
<li><code>app/assets</code>:存放当前应用程序用到的资源文件</li>
<li><code>lib/assets</code>:存放开发团队自己开发的代码库用到的资源文件</li>
<li><code>vendor/assets</code>:存放第三方代码库用到的资源文件</li>
</ul>
<p>你可能猜到了,上面的目录中都会有针对不同资源类型的子目录。例如:</p>
<div class="codeblock"><div class="highlight type-shell"><pre><span class="gp">$ </span>ls app/assets/
images javascripts stylesheets
</pre></div>
</div>
<p>现在我们就可以知道 <a href="chapter5.html#section-5-1-2">5.1.2 节</a>中 <code>custom.css.scss</code> 存放位置的用意:因为 <code>custom.css.scss</code> 是应用程序本身用到的,所以把它存放在 <code>app/assets/stylesheets</code> 中。</p>
<h4 id='section-5-2-1-2'><span></span>清单文件</h4>
<p>当你把资源文件存放在适当的目录后,要通过清单文件告诉 Rails怎么把它们合并成一个文件(使用 <a href="https://github.com/sstephenson/sprockets">Sprockets</a> gem。只适用于 CSS 和 JavaScript,而不会处理图片。)举个例子,让我们看一下应用程序默认的样式表清单文件(参见代码 5.15)。</p>
<div class="codeblock has-caption" id="codeblock-5-15"><p class="caption"><span>代码 5.15:</span>应用程序的样式表清单文件</p><p class="file"><code>app/assets/stylesheets/application.css</code></p><div class="highlight type-css"><pre><span class="c">/*
* This is a manifest file that'll automatically include all the stylesheets
* available in this directory and any sub-directories. You're free to add
* application-wide styles to this file and they'll appear at the top of the
* compiled file, but it's generally better to create a new file per style
* scope.
*= require_self
*= require_tree .
*/</span>
</pre></div>
</div>
<p>这里的关键代码是几行 CSS 注释,Sprockets 会通过这些注释加载相应的文件:</p>
<div class="codeblock"><div class="highlight type-css"><pre><span class="c">/*
* .
* .
* .
*= require_self
*= require_tree .
*/</span>
</pre></div>
</div>
<p>上面代码中的</p>
<div class="codeblock"><div class="highlight type-plaintext"><pre>*= require_tree .
</pre></div>
</div>
<p>会把 <code>app/assets/stylesheets</code> 目录中的所有 CSS 文件都引入应用程序的样式表中。</p>
<p>下面这行:</p>
<div class="codeblock"><div class="highlight type-plaintext"><pre>*= require_self
</pre></div>
</div>
<p>会把 <code>application.css</code> 这个文件中的 CSS 也加载进来。</p>
<p>Rails 提供的默认清单文件可以满足我们的要求,所以本书不会对其做任何修改。Rails 指南中有一篇专门<a href="http://guides.rubyonrails.org/asset_pipeline.html">介绍 asset pipeline 的文章</a>,该文有你需要知道的更为详细的内容。</p>
<h4 id='section-5-2-1-3'><span></span>预处理器引擎</h4>
<p>准备好资源文件后,Rails 会使用一些预处理器引擎来处理它们,通过清单文件将其合并,然后发送给浏览器。我们通过扩展名告诉 Rails 要使用哪个预处理器。三个最常用的扩展名是:Sass 文件的 <code>.scss</code>,CoffeeScript 文件的 <code>.coffee</code>,ERb 文件的 <code>.erb</code>。我们在 <a href="chapter3.html#section-3-3-3">3.3.3 节</a>介绍过 ERb,<a href="chapter5.html#section-5-2-2">5.2.2 节</a>会介绍 Sass。本教程不需要使用 CoffeeScript,这是一个很小巧的语言,可以编译成 JavaScript。(RailsCast 中<a href="http://railscasts.com/episodes/267-coffeescript-basics">关于 CoffeeScript 的视频</a>是个很好的入门教程。)</p>
<p>预处理器引擎可以连接在一起使用,因此</p>
<div class="codeblock"><div class="highlight type-plaintext"><pre>foobar.js.coffee
</pre></div>
</div>
<p>只会使用 CoffeeScript 处理器,而</p>
<div class="codeblock"><div class="highlight type-plaintext"><pre>foobar.js.erb.coffee
</pre></div>
</div>
<p>会使用 CoffeeScript 和 ERb 处理器(按照扩展名的顺序从右向左处理,所以 CoffeeScript 处理器会先执行)。</p>
<h4 id='section-5-2-1-4'><span></span>在生产环境中的效率问题</h4>
<p>Asset pipeline 带来的好处之一是,它会自动优化资源文件,在生产环境中使用效果极佳。CSS 和 JavaScript 的传统组织方式是将不同功能的代码放在不同的文件中,而且代码的格式是对人类友好的(有很多缩进)。虽然这对编程人员很友好,但在生产环境中使用却效率低下,加载大量的文件会明显增加页面加载时间(这是影响用户体验最主要的因素之一)。使用 asset pipeline,生产环境中应用程序所有的样式都会集中到一个 CSS 文件中(<code>application.css</code>),所有 JavaScript 代码都会集中到一个 JavaScript 文件中(<code>javascript.js</code>),而且还会压缩这些文件(包括 <code>lib/assets</code> 和 <code>vendor/assets</code> 中的相关文件),把不必要的空格删除,减小文件大小。这样我们就最好的平衡了两方面的需求:编程人员使用格式友好的多个文件,生产环境中使用优化后的单个文件。</p>
<h3 id='section-5-2-2'><span>5.2.2</span> 句法强大的样式表</h3>
<p>Sass 是一种编写 CSS 的语言,从多方面增强了 CSS 的功能。本节我们会介绍两个最主要的功能,嵌套和变量。(还有一个是 mixin,会在 <a href="chapter7.html#section-7-1-1">7.1.1 节</a>中介绍。)</p>
<p>如 <a href="chapter5.html#section-5-1-2">5.1.2 节</a>中的简单介绍,Sass 支持一种名为 SCSS 的格式(扩展名为 <code>.scss</code>),这是 CSS 句法的一个扩展集。SCSS 只是为 CSS 添加了一些功能,而没有定义全新的句法。<sup class="footnote" id="fnref-5-9"><a href="#fn-5-9" rel="footnote">9</a></sup>也就是说,所有合法的 CSS 文件都是合法的 SCSS 文件,这对已经定义了样式的项目来说是件好事。在我们的程序中,因为要使用 Bootstrap,从一开始就使用了 SCSS。Rails 的 asset pipeline 会自动使用 Sass 预处理器处理扩展名为 <code>.scss</code> 的文件,所以 <code>custom.css.scss</code> 文件会首先经由 Sass 预处理器处理,然后引入程序的样式表中,再发送给浏览器。</p>
<h4 id='section-5-2-2-1'><span></span>嵌套</h4>
<p>样式表中经常会定义嵌套元素的样式,例如,在代码 5.6 中,定义了 <code>.center</code> 和 <code>.center h1</code> 两个样式:</p>
<div class="codeblock"><div class="highlight type-css"><pre><span class="nc">.center</span> <span class="p">{</span>
<span class="nl">text-align</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.center</span> <span class="nt">h1</span> <span class="p">{</span>
<span class="nl">margin-bottom</span><span class="p">:</span> <span class="m">10px</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>使用 Sass 可将其改写成</p>
<div class="codeblock"><div class="highlight type-scss"><pre><span class="nc">.center</span> <span class="p">{</span>
<span class="nl">text-align</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
<span class="nt">h1</span> <span class="p">{</span>
<span class="nl">margin-bottom</span><span class="p">:</span> <span class="m">10px</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>上面代码中的 <code>h1</code> 会自动嵌入 <code>.center</code> 中。</p>
<p>嵌套还有另一种形式,句法稍有不同。在代码 5.8 中,有如下的代码</p>
<div class="codeblock"><div class="highlight type-css"><pre><span class="nf">#logo</span> <span class="p">{</span>
<span class="nl">float</span><span class="p">:</span> <span class="nb">left</span><span class="p">;</span>
<span class="nl">margin-right</span><span class="p">:</span> <span class="m">10px</span><span class="p">;</span>
<span class="nl">font-size</span><span class="p">:</span> <span class="m">1.7em</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="m">#fff</span><span class="p">;</span>
<span class="nl">text-transform</span><span class="p">:</span> <span class="nb">uppercase</span><span class="p">;</span>
<span class="nl">letter-spacing</span><span class="p">:</span> <span class="m">-1px</span><span class="p">;</span>
<span class="nl">padding-top</span><span class="p">:</span> <span class="m">9px</span><span class="p">;</span>
<span class="nl">font-weight</span><span class="p">:</span> <span class="nb">bold</span><span class="p">;</span>
<span class="nl">line-height</span><span class="p">:</span> <span class="m">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">#logo</span><span class="nd">:hover</span> <span class="p">{</span>
<span class="nl">color</span><span class="p">:</span> <span class="m">#fff</span><span class="p">;</span>
<span class="nl">text-decoration</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>其中 LOGO 的 id <code>#logo</code> 出现了两次,一次是单独出现的,另一次是和 <code>hover</code> 伪类一起出现的(鼠标悬停其上时的样式)。如果要嵌套第二个样式,我们需要引用父级元素 <code>#logo</code>,在 SCSS 中,使用 <code>&</code> 符号实现:</p>
<div class="codeblock"><div class="highlight type-scss"><pre><span class="nn">#logo</span> <span class="p">{</span>
<span class="nl">float</span><span class="p">:</span> <span class="nb">left</span><span class="p">;</span>
<span class="nl">margin-right</span><span class="p">:</span> <span class="m">10px</span><span class="p">;</span>
<span class="nl">font-size</span><span class="p">:</span> <span class="m">1</span><span class="mi">.7em</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="mh">#fff</span><span class="p">;</span>
<span class="nl">text-transform</span><span class="p">:</span> <span class="nb">uppercase</span><span class="p">;</span>
<span class="nl">letter-spacing</span><span class="p">:</span> <span class="m">-1px</span><span class="p">;</span>
<span class="nl">padding-top</span><span class="p">:</span> <span class="m">9px</span><span class="p">;</span>
<span class="nl">font-weight</span><span class="p">:</span> <span class="nb">bold</span><span class="p">;</span>
<span class="nl">line-height</span><span class="p">:</span> <span class="m">1</span><span class="p">;</span>
<span class="k">&</span><span class="nd">:hover</span> <span class="p">{</span>
<span class="nl">color</span><span class="p">:</span> <span class="mh">#fff</span><span class="p">;</span>
<span class="nl">text-decoration</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>把 SCSS 转换成 CSS 时,Sass 会把 <code>&:hover</code> 编译成 <code>#logo:hover</code>。</p>
<p>这两种嵌套方式都可以用于代码 5.14 中的底部样式上,转换后的样式如下:</p>
<div class="codeblock"><div class="highlight type-scss"><pre><span class="nt">footer</span> <span class="p">{</span>
<span class="nl">margin-top</span><span class="p">:</span> <span class="m">45px</span><span class="p">;</span>
<span class="nl">padding-top</span><span class="p">:</span> <span class="m">5px</span><span class="p">;</span>
<span class="nl">border-top</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="mh">#eaeaea</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="mh">#999</span><span class="p">;</span>
<span class="nt">a</span> <span class="p">{</span>
<span class="nl">color</span><span class="p">:</span> <span class="mh">#555</span><span class="p">;</span>
<span class="k">&</span><span class="nd">:hover</span> <span class="p">{</span>
<span class="nl">color</span><span class="p">:</span> <span class="mh">#222</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nt">small</span> <span class="p">{</span>
<span class="nl">float</span><span class="p">:</span> <span class="nb">left</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">ul</span> <span class="p">{</span>
<span class="nl">float</span><span class="p">:</span> <span class="nb">right</span><span class="p">;</span>
<span class="nl">list-style</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
<span class="nt">li</span> <span class="p">{</span>
<span class="nl">float</span><span class="p">:</span> <span class="nb">left</span><span class="p">;</span>
<span class="nl">margin-left</span><span class="p">:</span> <span class="m">10px</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>自己动手转换一下代码 5.14 是个不错的练习,转换之后你应该验证一下 CSS 是否还能正常使用。</p>
<h4 id='section-5-2-2-2'><span></span>变量</h4>
<p>Sass 允许我们自定义变量来避免重复,这样也可以写出更具表现力的代码。例如,代码 5.7 和代码 5.14 中都重复使用了同一个颜色代码:</p>
<div class="codeblock"><div class="highlight type-scss"><pre><span class="nt">h2</span> <span class="p">{</span>
<span class="err">.
.
.
</span><span class="nl">color</span><span class="p">:</span> <span class="mh">#999</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.</span>
<span class="nc">.</span>
<span class="nc">.</span>
<span class="nt">footer</span> <span class="p">{</span>
<span class="err">.
.
.
</span><span class="nl">color</span><span class="p">:</span> <span class="mh">#999</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>上面代码中的 <code>#999</code> 是淡灰色(ligh gray),我们可以为它定义一个变量:</p>
<div class="codeblock"><div class="highlight type-scss"><pre><span class="nv">$lightGray</span><span class="p">:</span> <span class="mh">#999</span><span class="p">;</span>
</pre></div>
</div>
<p>然后我们就可以这样写 SCSS:</p>
<div class="codeblock"><div class="highlight type-scss"><pre><span class="nv">$lightGray</span><span class="p">:</span> <span class="mh">#999</span><span class="p">;</span>
<span class="nc">.</span>
<span class="nc">.</span>
<span class="nc">.</span>
<span class="nt">h2</span> <span class="p">{</span>
<span class="err">.
.
.
</span><span class="nl">color</span><span class="p">:</span> <span class="nv">$lightGray</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.</span>
<span class="nc">.</span>
<span class="nc">.</span>
<span class="nt">footer</span> <span class="p">{</span>
<span class="err">.
.
.
</span><span class="nl">color</span><span class="p">:</span> <span class="nv">$lightGray</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>因为像 <code>$lightGray</code> 这样的变量名比 <code>#999</code> 更具说明性,所以为没有重复使用的值定义变量往往也是很有用的。Bootstrap 框架定义了很多颜色变量,<a href="http://bootstrapdocs.com/v2.0.4/docs/less.html">Bootstrap 页面中有这些变量的 LESS 形式</a>。这个页面中的变量使用的是 LESS 句法,而不是 Sass 句法,不过 bootstrap-sass gem 为我们提供了对应的 Sass 形式。二者之间的对应关系也不难猜出,LESS 使用 <code>@</code> 符号定义变量,而 Sass 使用 <code>$</code> 符号。在 Bootstrap 的变量页面我们可以看到为淡灰色定义的变量:</p>
<div class="codeblock"><div class="highlight type-scss"><pre><span class="k">@grayLight</span><span class="nd">:</span> <span class="nn">#999</span><span class="p">;</span>
</pre></div>
</div>
<p>也就是说,在 bootstrap-sass gem 中会有一个对应的 SCSS 变量 <code>$grayLight</code>。我们可以用它换掉自己定义的 <code>$lightGray</code> 变量:</p>
<div class="codeblock"><div class="highlight type-scss"><pre><span class="nt">h2</span> <span class="p">{</span>
<span class="err">.
.
.
</span><span class="nl">color</span><span class="p">:</span> <span class="nv">$grayLight</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.</span>
<span class="nc">.</span>
<span class="nc">.</span>
<span class="nt">footer</span> <span class="p">{</span>
<span class="err">.
.
.
</span><span class="nl">color</span><span class="p">:</span> <span class="nv">$grayLight</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>使用 Sass 提供的嵌套和变量功能后得到的完整 SCSS 文件如代码 5.16 所示。这段代码中使用了 Sass 形式的颜色变量(参照 Bootstrap 变量页面中定义的 LESS 形式的颜色变量)和内置的颜色名称(例如,<code>white</code> 代表 <code>#fff</code>)<sup class="footnote" id="fnref-5-t1"><a href="#fn-5-t1" rel="footnote">10</a></sup>。请特别注意一下 <code>footer</code> 标签样式明显的改进。</p>
<div class="codeblock has-caption" id="codeblock-5-16"><p class="caption"><span>代码 5.16:</span>使用嵌套和变量转换后的 SCSS 文件</p><p class="file"><code>app/assets/stylesheets/custom.css.scss</code></p><div class="highlight type-scss"><pre><span class="k">@import</span> <span class="s2">"bootstrap"</span><span class="p">;</span>
<span class="cm">/* mixins, variables, etc. */</span>
<span class="nv">$grayMediumLight</span><span class="p">:</span> <span class="mh">#eaeaea</span><span class="p">;</span>
<span class="cm">/* universal */</span>
<span class="nt">html</span> <span class="p">{</span>
<span class="nl">overflow-y</span><span class="p">:</span> <span class="nb">scroll</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">body</span> <span class="p">{</span>
<span class="nl">padding-top</span><span class="p">:</span> <span class="m">60px</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">section</span> <span class="p">{</span>
<span class="nl">overflow</span><span class="p">:</span> <span class="nb">auto</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">textarea</span> <span class="p">{</span>
<span class="nl">resize</span><span class="p">:</span> <span class="n">vertical</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.center</span> <span class="p">{</span>
<span class="nl">text-align</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
<span class="nt">h1</span> <span class="p">{</span>
<span class="nl">margin-bottom</span><span class="p">:</span> <span class="m">10px</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="cm">/* typography */</span>
<span class="nt">h1</span><span class="o">,</span> <span class="nt">h2</span><span class="o">,</span> <span class="nt">h3</span><span class="o">,</span> <span class="nt">h4</span><span class="o">,</span> <span class="nt">h5</span><span class="o">,</span> <span class="nt">h6</span> <span class="p">{</span>
<span class="nl">line-height</span><span class="p">:</span> <span class="m">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">h1</span> <span class="p">{</span>
<span class="nl">font-size</span><span class="p">:</span> <span class="m">3em</span><span class="p">;</span>
<span class="nl">letter-spacing</span><span class="p">:</span> <span class="m">-2px</span><span class="p">;</span>
<span class="nl">margin-bottom</span><span class="p">:</span> <span class="m">30px</span><span class="p">;</span>
<span class="nl">text-align</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">h2</span> <span class="p">{</span>
<span class="nl">font-size</span><span class="p">:</span> <span class="m">1</span><span class="mi">.2em</span><span class="p">;</span>
<span class="nl">letter-spacing</span><span class="p">:</span> <span class="m">-1px</span><span class="p">;</span>
<span class="nl">margin-bottom</span><span class="p">:</span> <span class="m">30px</span><span class="p">;</span>
<span class="nl">text-align</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
<span class="nl">font-weight</span><span class="p">:</span> <span class="nb">normal</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="nv">$grayLight</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">p</span> <span class="p">{</span>
<span class="nl">font-size</span><span class="p">:</span> <span class="m">1</span><span class="mi">.1em</span><span class="p">;</span>
<span class="nl">line-height</span><span class="p">:</span> <span class="m">1</span><span class="mi">.7em</span><span class="p">;</span>
<span class="p">}</span>
<span class="cm">/* header */</span>
<span class="nn">#logo</span> <span class="p">{</span>
<span class="nl">float</span><span class="p">:</span> <span class="nb">left</span><span class="p">;</span>
<span class="nl">margin-right</span><span class="p">:</span> <span class="m">10px</span><span class="p">;</span>
<span class="nl">font-size</span><span class="p">:</span> <span class="m">1</span><span class="mi">.7em</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="no">white</span><span class="p">;</span>
<span class="nl">text-transform</span><span class="p">:</span> <span class="nb">uppercase</span><span class="p">;</span>
<span class="nl">letter-spacing</span><span class="p">:</span> <span class="m">-1px</span><span class="p">;</span>
<span class="nl">padding-top</span><span class="p">:</span> <span class="m">9px</span><span class="p">;</span>
<span class="nl">font-weight</span><span class="p">:</span> <span class="nb">bold</span><span class="p">;</span>
<span class="nl">line-height</span><span class="p">:</span> <span class="m">1</span><span class="p">;</span>
<span class="k">&</span><span class="nd">:hover</span> <span class="p">{</span>
<span class="nl">color</span><span class="p">:</span> <span class="no">white</span><span class="p">;</span>
<span class="nl">text-decoration</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="cm">/* footer */</span>
<span class="nt">footer</span> <span class="p">{</span>
<span class="nl">margin-top</span><span class="p">:</span> <span class="m">45px</span><span class="p">;</span>
<span class="nl">padding-top</span><span class="p">:</span> <span class="m">5px</span><span class="p">;</span>
<span class="nl">border-top</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="nv">$grayMediumLight</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="nv">$grayLight</span><span class="p">;</span>
<span class="nt">a</span> <span class="p">{</span>
<span class="nl">color</span><span class="p">:</span> <span class="nv">$gray</span><span class="p">;</span>
<span class="k">&</span><span class="nd">:hover</span> <span class="p">{</span>
<span class="nl">color</span><span class="p">:</span> <span class="nv">$grayDarker</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nt">small</span> <span class="p">{</span>
<span class="nl">float</span><span class="p">:</span> <span class="nb">left</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">ul</span> <span class="p">{</span>
<span class="nl">float</span><span class="p">:</span> <span class="nb">right</span><span class="p">;</span>
<span class="nl">list-style</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
<span class="nt">li</span> <span class="p">{</span>
<span class="nl">float</span><span class="p">:</span> <span class="nb">left</span><span class="p">;</span>
<span class="nl">margin-left</span><span class="p">:</span> <span class="m">10px</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Sass 提供了很多功能,可以用来简化样式表,不过代码 5.16 只用到了最主要的功能,这是个好的开端。更多功能请查看 <a href="http://sass-lang.com/">Sass 网站</a>。</p>
<h2 id='section-5-3'><span>5.3</span> 布局中的链接</h2>
<p>我们已经为网站的布局定义了看起来还不错的样式,下面要把链接中暂时使用的占位符 <code>#</code> 换成真正的链接地址。当然,我们可以像下面这样手动加入链接:</p>
<div class="codeblock"><div class="highlight type-html"><pre><span class="nt"><a</span> <span class="na">href=</span><span class="s">"/static_pages/about"</span><span class="nt">></span>About<span class="nt"></a></span>
</pre></div>
</div>
<p>不过这样不太符合 Rails 风格。一者,“关于”页面的地址如果是 /about 而不是 /static_pages/about 就好了;再者,Rails 习惯使用具名路由(named route)来指定链接地址,相应的代码如下:</p>
<div class="codeblock"><div class="highlight type-erb"><pre><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"About"</span><span class="p">,</span> <span class="n">about_path</span> <span class="cp">%></span>
</pre></div>
</div>
<p>使用这种方式能更好的表达链接与 URI 和路由的对应关系,如<a href="chapter5.html#table-5-1">表格 5.1</a> 所示。本章完结之前除了最后一个链接之外,其他的链接都会设定好。(<a href="chapter8.html">第 8 章</a>会添加最后一个。)</p>
<div class="table has-caption" id="table-5-1"><p class="caption"><span>表格 5.1:</span>网站中链接的路由和 URL 地址的映射关系</p><table>
<thead>
<tr>
<th>页面</th>
<th>URL</th>
<th>对应的路由</th>
</tr>
</thead>
<tbody>
<tr>
<td>“首页”</td>
<td>/</td>
<td><code>root_path</code></td>