-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathchapter5.html
1761 lines (1510 loc) · 135 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>Ruby on Rails 教程 - 第 5 章 完善布局</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="description" content="最好的 Ruby on Rails 入门教程"/>
<meta name="keywords" content="ruby, rails, tutorial"/>
<meta name="author" content="Michael Hartl"/>
<meta name="translator" content="安道"/>
<meta name="generator" content="persie 0.0.1.beta.3"/>
<link rel="stylesheet" type="text/css" href="http://cdn.staticfile.org/twitter-bootstrap/3.2.0/css/bootstrap.min.css"/>
<link rel="stylesheet" type="text/css" href="http://cdn.staticfile.org/font-awesome/4.2.0/css/font-awesome.min.css"/>
<link rel="stylesheet" type="text/css" href="assets/style.css"/>
<script type="text/javascript" src="http://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript" src="http://cdn.staticfile.org/twitter-bootstrap/3.2.0/js/collapse.min.js"></script>
<script type="text/javascript" src="assets/global.js"></script>
</head>
<body>
<header class="navbar navbar-default navbar-fixed-top navbar-book">
<div class="container">
<div class="navbar-header">
<a href="http://railstutorial-china.org" class="navbar-brand">Ruby on Rails 教程</a>
<button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target=".book-navbar-collapse">
<span class="sr-only">导航</span>
<i class="fa fa-bars"></i>
</button>
<a href="http://railstutorial-china.org/#purchase" id="navbar-purchase-xs" class="btn btn-warning navbar-btn visible-xs collapsed-purchase-btn">购买</a>
</div>
<nav class="collapse navbar-collapse book-navbar-collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="http://railstutorial-china.org" title="首页">首页</a></li>
<li class="active"><a href="http://railstutorial-china.org/read/" title="在线阅读">阅读</a></li>
<li><a href="http://railstutorial-china.org/blog/" title="最新消息">博客</a></li>
<li><a href="https://selfstore.io/products/189/topics" title="论坛">论坛</a></li>
<li class="hidden-xs"><div><a href="http://railstutorial-china.org/#purchase" id="navbar-purchase" class="btn btn-warning navbar-btn" title="购买电子书">购买</a></div></li>
</ul>
</nav>
</div>
</header>
<div class="content">
<div class="container">
<div class="row">
<div class="col-lg-offset-2 col-lg-8">
<div class="alert alert-warning">
<p>在线版的内容可能落后于电子书,如果想及时获得更新,请<a href="http://railstutorial-china.org/#purchase" title="购买电子书">购买电子书</a>。</p>
</div>
<article class="article">
<section data-type="chapter" id="filling-in-the-layout">
<h1><span class="title-label">第 5 章</span> 完善布局</h1>
<p><a href="chapter4.html#rails-flavored-ruby">第 4 章</a>简介 Ruby 时,我们学习了如何在演示应用中引入样式表(<a href="chapter4.html#motivation">4.1 节</a>),不过现在样式表中还没有内容。本章我们要使用一个 CSS 框架,以及自己编写的样式,填充样式表。<sup>[<a id="fn-ref-1" href="#fn-1">1</a>]</sup>我们还要完善布局,添加指向各个页面的链接(例如首页和“关于”页面,<a href="#adding-some-structure">5.1 节</a>)。在这个过程中,我们会学习局部视图、Rails 路由和 Asset Pipeline,还会介绍 Sass(<a href="#sass-and-the-asset-pipeline">5.2 节</a>)。最后,我们还要向前迈出很重要的一步:允许用户在我们的网站中注册(<a href="#user-signup-a-first-step">5.4 节</a>)。</p>
<p>本章大部改动是添加和修改应用的布局,这些操作一般不由测试驱动,或者完全不用测试。所以大部分时间都花在文本编辑器和浏览器中,只用 TDD 添加“联系”页面(<a href="#contact-page">5.3.1 节</a>)。不过,我们要编写一种重要的测试,集成测试,检查最终完成的布局中有所需的链接(<a href="#layout-link-tests">5.3.4 节</a>)。</p>
<section data-type="sect1" id="adding-some-structure">
<h1><span class="title-label">5.1</span> 添加一些结构</h1>
<p>本书介绍 Web 开发而不是 Web 设计,不过在一个看起来很简陋的应用中开发会让人提不起劲,所以本节要向布局中添加一些结构,再加入一些 CSS 实现基本的样式。除了使用自定义的 CSS 之外,我们还会使用由 Twitter 开发的开源 Web 设计框架 <a href="http://getbootstrap.com/">Bootstrap</a>。我们会按照一定的方式组织代码——当布局文件中的内容变多以后,使用局部视图清理。</p>
<p>开发 Web 应用时,尽早对用户界面有个统筹安排往往会对你有所帮助。在本书后续内容中,我会经常使用网页构思图(mockup)(在 Web 领域经常称之为“线框图”),展示应用最终外观的草图。<sup>[<a id="fn-ref-2" href="#fn-2">2</a>]</sup>本章大部分内容都在开发 <a href="chapter3.html#static-pages">3.2 节</a>编写的静态页面,我们要在页面中加入一个网站 LOGO、导航条和网站底部。这些页面中最重要的是“首页”,它的构思图如<a href="#fig-home-page-mockup">图 5.1</a> 所示,<a href="#fig-site-with-footer">图 5.7</a> 是最终实现的效果。你会发现二者之间的某些细节有所不同,例如,在最终实现的页面中我们加入了一个 Rails LOGO——这没什么关系,因为构思图没必要画出每个细节。</p>
<div id="fig-home-page-mockup" class="figure"><img src="images/chapter5/home_page_mockup_3rd_edition.png" alt="home page mockup 3rd edition" /><div class="figcaption"><span class="title-label">图 5.1</span>:演示应用首页的构思图</div></div>
<p>和之前一样,如果使用 Git 做版本控制,现在最好创建一个新分支:</p>
<div data-type="listing">
<div class="highlight language-sh"><pre><span class="nv">$ </span>git checkout master
<span class="nv">$ </span>git checkout -b filling-in-layout
</pre></div>
</div>
<section data-type="sect2" id="site-navigation">
<h2><span class="title-label">5.1.1</span> 网站导航</h2>
<p>在应用中添加链接和样式之前,我们先来修改网站的布局文件 <code>application.html.erb</code>(上一次见到是在<a href="chapter4.html#listing-application-layout-full-title">代码清单 4.3</a> 中),添加一些 HTML 结构。我们要添加一些区域,一些 CSS 类,以及导航条。布局文件的完整内容参见<a href="#listing-layout-new-structure">代码清单 5.1</a>,
对各部分的说明紧跟其后。如果你迫不及待想看到结果,请看<a href="#fig-layout-no-logo-or-custom-css">图 5.2</a>。(注意:结果(还)不是很让人满意。)</p>
<div id="listing-layout-new-structure" data-type="listing">
<h5><span class="title-label">代码清单 5.1</span>:添加一些结构后的网站布局文件</h5>
<div class="source-file">app/views/layouts/application.html.erb</div>
<div class="highlight language-erb"><pre><span class="x"><!DOCTYPE html></span>
<span class="x"><html></span>
<span class="x"> <head></span>
<span class="x"> <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="x"></title></span>
<span class="x"> </span><span class="cp"><%=</span> <span class="n">stylesheet_link_tag</span> <span class="s1">'application'</span><span class="p">,</span> <span class="ss">media</span><span class="p">:</span> <span class="s1">'all'</span><span class="p">,</span>
<span class="s1">'data-turbolinks-track'</span> <span class="o">=></span> <span class="kp">true</span> <span class="cp">%></span><span class="x"></span>
<span class="x"> </span><span class="cp"><%=</span> <span class="n">javascript_include_tag</span> <span class="s1">'application'</span><span class="p">,</span> <span class="s1">'data-turbolinks-track'</span> <span class="o">=></span> <span class="kp">true</span> <span class="cp">%></span><span class="x"></span>
<span class="x"> </span><span class="cp"><%=</span> <span class="n">csrf_meta_tags</span> <span class="cp">%></span><span class="x"></span>
<span class="x"> <!--[if lt IE 9]></span>
<span class="x"> <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js"></span>
<span class="x"> </script></span>
<span class="x"> <![endif]--></span>
<span class="x"> </head></span>
<span class="x"> <body></span>
<span class="x"> <header class="navbar navbar-fixed-top navbar-inverse"></span>
<span class="x"> <div class="container"></span>
<span class="x"> </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="nb">id</span><span class="p">:</span> <span class="s2">"logo"</span> <span class="cp">%></span><span class="x"></span>
<span class="x"> <nav></span>
<span class="x"> <ul class="nav navbar-nav navbar-right"></span>
<span class="x"> <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="x"></li></span>
<span class="x"> <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="x"></li></span>
<span class="x"> <li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Log in"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="x"></li></span>
<span class="x"> </ul></span>
<span class="x"> </nav></span>
<span class="x"> </div></span>
<span class="x"> </header></span>
<span class="x"> <div class="container"></span>
<span class="x"> </span><span class="cp"><%=</span> <span class="k">yield</span> <span class="cp">%></span><span class="x"></span>
<span class="x"> </div></span>
<span class="x"> </body></span>
<span class="x"></html></span>
</pre></div>
</div>
<p>我们从上往下看一下这段代码中新添加的元素。<a href="chapter3.html#testing-titles">3.4.1 节</a>简单介绍过,Rails 默认使用 HTML5(如 <code><!DOCTYPE html></code> 所示)。因为 HTML5 标准还很新,有些浏览器(特别是旧版 IE 浏览器)还没有完全支持,所以我们加载了一些 JavaScript 代码(称作“<a href="https://github.com/aFarkas/html5shiv">HTML5 shim</a>”)来解决这个问题:</p>
<div data-type="listing">
<div class="highlight language-html"><pre><span class="c"><!--[if lt IE 9]></span>
<span class="c"> <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js"></span>
<span class="c"> </script></span>
<span class="c"><![endif]--></span>
</pre></div>
</div>
<p>如下有点古怪的句法</p>
<div data-type="listing">
<div class="highlight language-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>。使用这个句法有个好处,只会在 IE9 以前的版本中加载 HTML5 shim,而 Firefox、Chrome 和 Safari 等其他浏览器不会受到影响。</p>
<p>后面的区域是一个 <code>header</code>,包含网站的 LOGO(纯文本)、一些区域(使用 <code>div</code> 标签)和一个导航列表元素:</p>
<div data-type="listing">
<div class="highlight language-erb"><pre><span class="x"><header class="navbar navbar-fixed-top navbar-inverse"></span>
<span class="x"> <div class="container"></span>
<span class="x"> </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="nb">id</span><span class="p">:</span> <span class="s2">"logo"</span> <span class="cp">%></span><span class="x"></span>
<span class="x"> <nav></span>
<span class="x"> <ul class="nav navbar-nav navbar-right"></span>
<span class="x"> <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="x"></li></span>
<span class="x"> <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="x"></li></span>
<span class="x"> <li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Log in"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="x"></li></span>
<span class="x"> </ul></span>
<span class="x"> </nav></span>
<span class="x"> </div></span>
<span class="x"></header></span>
</pre></div>
</div>
<p><code>header</code> 标签表明这个元素应该放在页面的顶部。我们为 <code>header</code> 标签指定了三个 CSS 类,<sup>[<a id="fn-ref-3" href="#fn-3">3</a>]</sup>分别为 <code>navbar</code>、<code>navbar-fixed-top</code> 和 <code>navbar-inverse</code>,类之间用空格分开:</p>
<div data-type="listing">
<div class="highlight language-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 元素都可以指定类和 ID,它们不仅是标记,使用 CSS 编写样式时也有用(<a href="#bootstrap-and-custom-css">5.1.2 节</a>)。类和 ID 之间主要的区别是,类可以在同一个网页中多次使用,而 ID 只能使用一次。这里的三个类在 Bootstrap 框架中都有特殊的意义。我们会在 <a href="#bootstrap-and-custom-css">5.1.2 节</a>安装并使用 Bootstrap。</p>
<p>在 <code>header</code> 标签内部,有一个 <code>div</code> 标签:</p>
<div data-type="listing">
<div class="highlight language-html"><pre><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 类,<code>container</code>。和 <code>header</code> 标签的类一样,这个类在 Bootstrap 中也有特殊的意义。</p>
<p>在这个 <code>div</code> 标签中有一些 ERb 代码:</p>
<div data-type="listing">
<div class="highlight language-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="nb">id</span><span class="p">:</span> <span class="s2">"logo"</span> <span class="cp">%></span><span class="x"></span>
<span class="x"><nav></span>
<span class="x"> <ul class="nav navbar-nav navbar-right"></span>
<span class="x"> <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="x"></li></span>
<span class="x"> <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="x"></li></span>
<span class="x"> <li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Log in"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="x"></li></span>
<span class="x"> </ul></span>
<span class="x"></nav></span>
</pre></div>
</div>
<p>这里使用 Rails 提供的 <code>link_to</code> 辅助方法创建链接(<a href="chapter3.html#custom-static-pages">3.2.2 节</a>直接使用 <code>a</code> 标签创建)。<code>link_to</code> 的第一个参数是链接文本,第二个参数是链接地址。在 <a href="#layout-links">5.3 节</a>我们会使用“具名路由”(named route)指定链接地址,现在暂且使用 Web 开发中经常使用的占位符 <code>#</code>。第三个参数可选,是一个哈希,本例使用这个参数为 LOGO 添加一个 CSS ID——<code>logo</code>。(其他三个链接没有使用这个哈希参数,没关系,因为这个参数是可选的。)Rails 辅助方法的参数经常这样使用哈希,让我们仅使用 Rails 的辅助方法就能灵活添加 HTML 属性。</p>
<p><code>div</code> 标签中的第二个元素是导航链接,使用无序列表标签 <code>ul</code>,以及列表项目标签 <code>li</code> 编写:</p>
<div data-type="listing">
<div class="highlight language-erb"><pre><span class="x"><nav></span>
<span class="x"> <ul class="nav navbar-nav navbar-right"></span>
<span class="x"> <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="x"></li></span>
<span class="x"> <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="x"></li></span>
<span class="x"> <li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Log in"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="x"></li></span>
<span class="x"> </ul></span>
<span class="x"></nav></span>
</pre></div>
</div>
<p><code>nav</code> 标签以前是不需要的,它的目的是明确表明这些链接是导航。<code>ul</code> 标签中的 <code>nav</code>、<code>navbar-nav</code> 和 <code>navbar-right</code> 三个类在 Bootstrap 中有特殊的意义,<a href="#bootstrap-and-custom-css">5.1.2 节</a>引入 Bootstrap 的 CSS 之后会自动实现特殊的样式。在浏览器中审查导航元素,你会发现 Rails 处理布局文件并执行其中的 ERb 代码后,生成的列表如下所示:<sup>[<a id="fn-ref-4" href="#fn-4">4</a>]</sup></p>
<div data-type="listing">
<div class="highlight language-html"><pre><span class="nt"><nav></span>
<span class="nt"><ul</span> <span class="na">class=</span><span class="s">"nav navbar-nav navbar-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>Log in<span class="nt"></a></li></span>
<span class="nt"></ul></span>
<span class="nt"></nav></span>
</pre></div>
</div>
<p>这就是返回给浏览器的文本。</p>
<p>布局文件的最后一部分是一个 <code>div</code> 标签,用于显示主内容:</p>
<div data-type="listing">
<div class="highlight language-erb"><pre><span class="x"><div class="container"></span>
<span class="x"> </span><span class="cp"><%=</span> <span class="k">yield</span> <span class="cp">%></span><span class="x"></span>
<span class="x"></div></span>
</pre></div>
</div>
<p>和之前一样,<code>container</code> 类在 Bootstrap 中有特殊意义。<a href="chapter3.html#layouts-and-embedded-ruby">3.4.3 节</a>已经介绍过,<code>yield</code> 会把各页面中的内容插入网站的布局中。</p>
<p>除了网站的底部(<a href="#partials">5.1.3 节</a>会添加)之外,布局现在完成了。访问“首页”就能看到结果。为了利用后面添加的样式,我们要在 <code>home.html.erb</code> 视图中添加一些额外元素,如<a href="#listing-signup-button">代码清单 5.2</a> 所示。</p>
<div id="listing-signup-button" data-type="listing">
<h5><span class="title-label">代码清单 5.2</span>:“首页”视图,包含一个到注册页面的链接</h5>
<div class="source-file">app/views/static_pages/home.html.erb</div>
<div class="highlight language-erb"><pre><span class="x"><div class="center jumbotron"></span>
<span class="x"> <h1>Welcome to the Sample App</h1></span>
<span class="x"> <h2></span>
<span class="x"> This is the home page for the</span>
<span class="x"> <a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a></span>
<span class="x"> sample application.</span>
<span class="x"> </h2></span>
<span class="x"> </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="p">:</span> <span class="s2">"btn btn-lg btn-primary"</span> <span class="cp">%></span><span class="x"></span>
<span class="x"></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="p">:</span> <span class="s2">"Rails logo"</span><span class="p">),</span>
<span class="s1">'http://rubyonrails.org/'</span> <span class="cp">%></span><span class="x"></span>
</pre></div>
</div>
<p>其中第一个 <code>link_to</code> 创建一个占位链接,指向<a href="chapter7.html#sign-up">第 7 章</a>创建的用户注册页面:</p>
<div data-type="listing">
<div class="highlight language-erb"><pre><span class="x"><a href="#" class="btn btn-lg btn-primary">Sign up now!</a></span>
</pre></div>
</div>
<p><code>div</code> 标签的 CSS 类 <code>jumbotron</code> 在 Bootstrap 中有特殊的意义,注册按钮的 <code>btn</code>、<code>btn-lg</code> 和 <code>btn-primary</code> 也是一样。</p>
<p>第二个 <code>link_to</code> 用到了 <code>image_tag</code> 辅助方法,第一个参数是图片的路径;第二个参数可选,是一个哈希,本例中这个哈希参数使用一个符号键设置图片的 <code>alt</code> 属性。为了能正确显示图片,应用中必须有个名为 <code>rails.png</code> 的图片。这个图片可以从本书的网站中下载,地址是 <a href="http://railstutorial-china.org/assets/images/rails.png">http://railstutorial-china.org/assets/images/rails.png</a>。下载后把这个图片放在 <code>app/assets/images/</code> 文件夹中。如果使用云端 IDE 或 Unix 类系统,可以使用 <code>curl</code> 完成这个操作,如下所示:<sup>[<a id="fn-ref-5" href="#fn-5">5</a>]</sup></p>
<div data-type="listing">
<div class="highlight language-sh"><pre><span class="nv">$ </span>curl -O http://railstutorial-china.org/assets/images/rails.png
<span class="nv">$ </span>mv rails.png app/assets/images/
</pre></div>
</div>
<p>因为我们使用了 <code>image_tag</code> 辅助方法,所以 Rails 会使用 Asset Pipeline(<a href="#sass-and-the-asset-pipeline">5.2 节</a>)自动在 <code>app/assets/images/</code> 文件夹中寻找图片。</p>
<p>为了更好地理解 <code>image_tag</code>,我们来看一下生成的 HTML:<sup>[<a id="fn-ref-6" href="#fn-6">6</a>]</sup></p>
<div data-type="listing">
<div class="highlight language-html"><pre><span class="nt"><img</span> <span class="na">alt=</span><span class="s">"Rails logo"</span> <span class="na">src=</span><span class="s">"/assets/rails-9308b8f92fea4c19a3a0d8385b494526.png"</span> <span class="nt">/></span>
</pre></div>
</div>
<p>其中,字符串 <code>9308b8f92fea4c19a3a0d8385b494526</code>(在你的系统中得到的字符串可能不一样)由 Rails 添加,目的是确保文件名的唯一性,如果文件变化了,让浏览器重新加载文件(而不是从缓存中读取)。注意,<code>src</code> 属性中并没有 <code>images</code>,使用的是静态文件(图片,JavaScript,CSS 等)共用的 <code>assets</code> 文件夹。在服务器中,Rails 会把 <code>assets</code> 文件夹中的图片和 <code>app/assets/images</code> 文件夹中的文件对应起来。这么做是为了让浏览器觉得所有静态文件都在同一个文件夹中,有利于快速伺服。<code>alt</code> 属性的内容会在图片无法加载时显示,例如在针对视觉障碍人士的屏幕阅读器中。</p>
<div id="fig-layout-no-logo-or-custom-css" class="figure"><img src="images/chapter5/layout_no_logo_or_custom_css_bootstrap_3rd_edition.png" alt="layout no logo or custom css bootstrap 3rd edition" /><div class="figcaption"><span class="title-label">图 5.2</span>:还没添加 CSS 的首页</div></div>
<p>现在我们终于可以看到劳动的果实了,如<a href="#fig-layout-no-logo-or-custom-css">图 5.2</a> 所示。你可能会说,这并不很美观啊。或许吧。不过也可以小小的高兴一下,因为我们为 HTML 结构指定了合适的类,可以用来添加 CSS。</p>
</section>
<section data-type="sect2" id="bootstrap-and-custom-css">
<h2><span class="title-label">5.1.2</span> Bootstrap 和自定义的 CSS</h2>
<p>前一节我们为很多 HTML 元素指定了 CSS 类,这样我们就可以使用 CSS 灵活的构建布局了。如前所述,其中很多类在 Bootstrap 中都有特殊的意义。Bootstrap 是 Twitter 开发的框架,可以方便地把精美的 Web 设计和用户界面元素添加到使用 HTML5 开发的应用中。本节,我们会结合 Bootstrap 和一些自定义的 CSS 为演示应用添加一些样式。</p>
<p>首先,我们要安装 Bootstrap。在 Rails 应用中可以使用 <code>bootstrap-sass</code> 这个 gem,如<a href="#listing-bootstrap-sass">代码清单 5.3</a> 所示。Bootstrap 框架本身使用 <a href="http://lesscss.org/">LESS</a> 编写动态样式表,而 Rails 的 Asset Pipeline 默认支持的是(非常类似的)Sass 语言。<code>bootstrap-sass</code> 会把 LESS 转换成 Sass,而且让 Bootstrap 中所有必要的文件都可以在当前应用中使用。<sup>[<a id="fn-ref-7" href="#fn-7">7</a>]</sup></p>
<div id="listing-bootstrap-sass" data-type="listing">
<h5><span class="title-label">代码清单 5.3</span>:把 <code>bootstrap-sass</code> 添加到 <code>Gemfile</code> 中</h5>
<div class="highlight language-ruby"><pre><span class="n">source</span> <span class="s1">'https://rubygems.org'</span>
<span class="n">gem</span> <span class="s1">'rails'</span><span class="p">,</span> <span class="s1">'4.2.2'</span>
<span class="n">gem</span> <span class="s1">'bootstrap-sass'</span><span class="p">,</span> <span class="s1">'3.2.0.0'</span>
<span class="o">.</span>
<span class="o">.</span>
<span class="o">.</span>
</pre></div>
</div>
<p>和之前一样,运行 <code>bundle install</code> 安装 Bootstrap:</p>
<div data-type="listing">
<div class="highlight language-sh"><pre><span class="nv">$ </span>bundle install
</pre></div>
</div>
<p><code>rails generate</code> 命令会自动为控制器生成一个单独的 CSS 文件,但很难使用正确的顺序引入这些样式,所以简单起见,本书会把所有 CSS 都放在一个文件夹中。为此,我们要先新建这个 CSS 文件:</p>
<div data-type="listing">
<div class="highlight language-sh"><pre><span class="nv">$ </span>touch app/assets/stylesheets/custom.css.scss
</pre></div>
</div>
<p>(使用 <a href="chapter3.html#green">3.3.3 节</a>用过的 <code>touch</code> 命令,你也可以使用其他方式。)其中文件夹的名字和文件扩展名都很重要。<code>app/assets/stylesheets/</code> 文件夹是 Asset Pipeline 的一部分,其中所有的样式表都会引入 <code>application.css</code> 文件。文件名 <code>custom.css.scss</code> 中包含 <code>.css</code>,说明这是 CSS 文件,<code>.scss</code> 扩展名则说明这是“Sassy CSS”文件,Asset Pipeline 会使用 Sass 处理其中的内容。(<a href="#syntactically-awesome-stylesheets">5.2.2 节</a>才会使用 Sass,不过加入这个扩展名才能发挥 <code>bootstrap-sass</code> gem 的作用。)</p>
<p>在这个 CSS 文件中,我们可以使用 <code>@import</code> 函数引入 Bootstrap(以及相关的 Sprockets 工具),如<a href="#listing-bootstrap-css">代码清单 5.4</a> 所示。<sup>[<a id="fn-ref-8" href="#fn-8">8</a>]</sup></p>
<div id="listing-bootstrap-css" data-type="listing">
<h5><span class="title-label">代码清单 5.4</span>:添加 Bootstrap 的 CSS</h5>
<div class="source-file">app/assets/stylesheets/custom.css.scss</div>
<div class="highlight language-scss"><pre><span class="k">@import</span> <span class="s2">"bootstrap-sprockets"</span><span class="p">;</span>
<span class="k">@import</span> <span class="s2">"bootstrap"</span><span class="p">;</span>
</pre></div>
</div>
<p>这两行代码会引入整个 Bootstrap CSS 框架。然后重启 Web 服务器(先按 Ctrl-C 键,然后执行 <code>rails server</code> 命令),让这些改动生效,效果如<a href="#fig-sample-app-only-bootstrap">图 5.3</a> 所示。文本的位置还不合适,LOGO 也没有任何样式,不过颜色搭配和注册按钮看起来都不错。</p>
<div id="fig-sample-app-only-bootstrap" class="figure"><img src="images/chapter5/sample_app_only_bootstrap_3rd_edition.png" alt="sample app only bootstrap 3rd edition" /><div class="figcaption"><span class="title-label">图 5.3</span>:使用 Bootstrap CSS 后的演示应用</div></div>
<p>下面我们要加入一些整站都会用到的 CSS,用来样式化网站布局和各个页面,如<a href="#listing-universal-css">代码清单 5.5</a> 所示。效果如<a href="#fig-sample-app-universal">图 5.4</a> 所示。代码清单 5.5 中定义了很多样式规则。为了说明 CSS 规则的作用,经常会加入一些 CSS 注释,放在 <code>/* ... */</code> 中。</p>
<div id="listing-universal-css" data-type="listing">
<h5><span class="title-label">代码清单 5.5</span>:添加全站使用的 CSS</h5>
<div class="source-file">app/assets/stylesheets/custom.css.scss</div>
<div class="highlight language-scss"><pre><span class="k">@import</span> <span class="s2">"bootstrap-sprockets"</span><span class="p">;</span>
<span class="k">@import</span> <span class="s2">"bootstrap"</span><span class="p">;</span>
<span class="cm">/* universal */</span>
<span class="nt">body</span> <span class="p">{</span>
<span class="na">padding-top</span><span class="o">:</span> <span class="mi">60</span><span class="kt">px</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">section</span> <span class="p">{</span>
<span class="na">overflow</span><span class="o">:</span> <span class="no">auto</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">textarea</span> <span class="p">{</span>
<span class="na">resize</span><span class="o">:</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="na">text-align</span><span class="o">:</span> <span class="no">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="na">margin-bottom</span><span class="o">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<div id="fig-sample-app-universal" class="figure"><img src="images/chapter5/sample_app_universal_3rd_edition.png" alt="sample app universal 3rd edition" /><div class="figcaption"><span class="title-label">图 5.4</span>:添加一些留白以及其他全局样式</div></div>
<p>注意,<a href="#listing-universal-css">代码清单 5.5</a> 中的 CSS 格式都是统一的。一般来说,CSS 规则通过类、ID、HTML 标签或者三者结合在一起来指代目标,然后在后面跟着一些样式声明。例如:</p>
<div data-type="listing">
<div class="highlight language-css"><pre><span class="nt">body</span> <span class="p">{</span>
<span class="k">padding-top</span><span class="o">:</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> 类,Bootstrap 会把这个导航条固定在页面的顶部,所以页面的上内边距会把主内容区和导航条隔开一段距离。(导航条的颜色在 Bootstrap 2.0 中变了,所以我们要加入 <code>navbar-inverse</code> 类,把亮色变暗。)下面的 CSS 规则:</p>
<div data-type="listing">
<div class="highlight language-css"><pre><span class="nc">.center</span> <span class="p">{</span>
<span class="k">text-align</span><span class="o">:</span> <span class="k">center</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>把 <code>.center</code> 类的样式定义为 <code>text-align: center;</code>。<code>.center</code> 中的点号说明这个规则是样式化一个类。(在<a href="#listing-logo-css">代码清单 5.7</a> 中会看到,<code>#</code> 样式化一个 ID。)这个规则的意思是,任何类为 <code>.center</code> 的标签(例如 <code>div</code>),其中包含的内容都会在页面中居中显示。(<a href="#listing-signup-button">代码清单 5.2</a> 中有用到这个类。)</p>
<p>虽然 Bootstrap 中包含了很精美的文字排版样式,我们还是要为文字的外观添加一些自定义的规则,如<a href="#listing-typography-css">代码清单 5.6</a> 所示。(并不是所有样式都用于“首页”,但所有规则都会在这个演示应用的某个地方用到。)效果如<a href="#fig-sample-app-typography">图 5.5</a> 所示。</p>
<div id="listing-typography-css" data-type="listing">
<h5><span class="title-label">代码清单 5.6</span>:添加一些精美的文字排版样式</h5>
<div class="source-file">app/assets/stylesheets/custom.css.scss</div>
<div class="highlight language-scss"><pre><span class="k">@import</span> <span class="s2">"bootstrap-sprockets"</span><span class="p">;</span>
<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="na">line-height</span><span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">h1</span> <span class="p">{</span>
<span class="na">font-size</span><span class="o">:</span> <span class="mi">3</span><span class="kt">em</span><span class="p">;</span>
<span class="na">letter-spacing</span><span class="o">:</span> <span class="mi">-2</span><span class="kt">px</span><span class="p">;</span>
<span class="na">margin-bottom</span><span class="o">:</span> <span class="mi">30</span><span class="kt">px</span><span class="p">;</span>
<span class="na">text-align</span><span class="o">:</span> <span class="no">center</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">h2</span> <span class="p">{</span>
<span class="na">font-size</span><span class="o">:</span> <span class="mi">1</span><span class="mf">.2</span><span class="kt">em</span><span class="p">;</span>
<span class="na">letter-spacing</span><span class="o">:</span> <span class="mi">-1</span><span class="kt">px</span><span class="p">;</span>
<span class="na">margin-bottom</span><span class="o">:</span> <span class="mi">30</span><span class="kt">px</span><span class="p">;</span>
<span class="na">text-align</span><span class="o">:</span> <span class="no">center</span><span class="p">;</span>
<span class="na">font-weight</span><span class="o">:</span> <span class="no">normal</span><span class="p">;</span>
<span class="na">color</span><span class="o">:</span> <span class="mh">#777</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">p</span> <span class="p">{</span>
<span class="na">font-size</span><span class="o">:</span> <span class="mi">1</span><span class="mf">.1</span><span class="kt">em</span><span class="p">;</span>
<span class="na">line-height</span><span class="o">:</span> <span class="mi">1</span><span class="mf">.7</span><span class="kt">em</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<div id="fig-sample-app-typography" class="figure"><img src="images/chapter5/sample_app_typography_3rd_edition.png" alt="sample app typography 3rd edition" /><div class="figcaption"><span class="title-label">图 5.5</span>:添加一些排版样式</div></div>
<p>最后,我们还要为只包含文本“sample app”的网站 LOGO 添加一些样式。<a href="#listing-logo-css">代码清单 5.7</a> 中的 CSS 会把文字变成全大写字母,还修改了文字大小、颜色和位置。(我们使用的是 ID,因为我们希望 LOGO 在页面中只出现一次,不过也可以使用类。)</p>
<div id="listing-logo-css" data-type="listing">
<h5><span class="title-label">代码清单 5.7</span>:添加网站 LOGO 的样式</h5>
<div class="source-file">app/assets/stylesheets/custom.css.scss</div>
<div class="highlight language-scss"><pre><span class="k">@import</span> <span class="s2">"bootstrap-sprockets"</span><span class="p">;</span>
<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="na">float</span><span class="o">:</span> <span class="no">left</span><span class="p">;</span>
<span class="na">margin-right</span><span class="o">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
<span class="na">font-size</span><span class="o">:</span> <span class="mi">1</span><span class="mf">.7</span><span class="kt">em</span><span class="p">;</span>
<span class="na">color</span><span class="o">:</span> <span class="mh">#fff</span><span class="p">;</span>
<span class="na">text-transform</span><span class="o">:</span> <span class="no">uppercase</span><span class="p">;</span>
<span class="na">letter-spacing</span><span class="o">:</span> <span class="mi">-1</span><span class="kt">px</span><span class="p">;</span>
<span class="na">padding-top</span><span class="o">:</span> <span class="mi">9</span><span class="kt">px</span><span class="p">;</span>
<span class="na">font-weight</span><span class="o">:</span> <span class="no">bold</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="na">color</span><span class="o">:</span> <span class="mh">#fff</span><span class="p">;</span>
<span class="na">text-decoration</span><span class="o">:</span> <span class="no">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>。添加<a href="#listing-logo-css">代码清单 5.7</a> 中的样式后,效果如<a href="#fig-sample-app-logo">图 5.6</a> 所示。</p>
<div id="fig-sample-app-logo" class="figure"><img src="images/chapter5/sample_app_logo_3rd_edition.png" alt="sample app logo 3rd edition" /><div class="figcaption"><span class="title-label">图 5.6</span>:添加 LOGO 样式后的演示应用</div></div>
</section>
<section data-type="sect2" id="partials">
<h2><span class="title-label">5.1.3</span> 局部视图</h2>
<p>虽然<a href="#listing-layout-new-structure">代码清单 5.1</a> 中的布局达到了目的,但其中的内容看起来有点混乱。HTML shim 就占用了三行,而且使用了只针对 IE 的奇怪句法,如果能把它打包放在一个单独的地方就好了。头部的 HTML 自成一个逻辑单元,所以也可以把这部分打包放在某个地方。在 Rails 中我们可以使用“局部视图”实现这种想法。先来看一下定义了局部视图之后的布局文件。如<a href="#listing-layout-with-partials">代码清单 5.8</a> 所示。</p>
<div id="listing-layout-with-partials" data-type="listing">
<h5><span class="title-label">代码清单 5.8</span>:把 HTML shim 和头部放到局部视图之后的网站布局</h5>
<div class="source-file">app/views/layouts/application.html.erb</div>
<div class="highlight language-erb"><pre><span class="x"><!DOCTYPE html></span>
<span class="x"><html></span>
<span class="x"> <head></span>
<span class="x"> <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="x"></title></span>
<span class="x"> </span><span class="cp"><%=</span> <span class="n">stylesheet_link_tag</span> <span class="s1">'application'</span><span class="p">,</span> <span class="ss">media</span><span class="p">:</span> <span class="s1">'all'</span><span class="p">,</span>
<span class="s1">'data-turbolinks-track'</span> <span class="o">=></span> <span class="kp">true</span> <span class="cp">%></span><span class="x"></span>
<span class="x"> </span><span class="cp"><%=</span> <span class="n">javascript_include_tag</span> <span class="s1">'application'</span><span class="p">,</span> <span class="s1">'data-turbolinks-track'</span> <span class="o">=></span> <span class="kp">true</span> <span class="cp">%></span><span class="x"></span>
<span class="x"> </span><span class="cp"><%=</span> <span class="n">csrf_meta_tags</span> <span class="cp">%></span><span class="x"></span>
<span class="hll"><span class="x"> </span><span class="cp"><%=</span> <span class="n">render</span> <span class="s1">'layouts/shim'</span> <span class="cp">%></span><span class="x"></span>
</span><span class="x"> </head></span>
<span class="x"> <body></span>
<span class="hll"><span class="x"> </span><span class="cp"><%=</span> <span class="n">render</span> <span class="s1">'layouts/header'</span> <span class="cp">%></span><span class="x"></span>
</span><span class="x"> <div class="container"></span>
<span class="x"> </span><span class="cp"><%=</span> <span class="k">yield</span> <span class="cp">%></span><span class="x"></span>
<span class="x"> </div></span>
<span class="x"> </body></span>
<span class="x"></html></span>
</pre></div>
</div>
<p>在这段代码中,我们把 HTML shim 删掉,换成了一行代码,调用 Rails 的辅助方法 <code>render</code>:</p>
<div data-type="listing">
<div class="highlight language-erb"><pre><span class="cp"><%=</span> <span class="n">render</span> <span class="s1">'layouts/shim'</span> <span class="cp">%></span><span class="x"></span>
</pre></div>
</div>
<p>这行代码会寻找一个名为 <code>app/views/layouts/_shim.html.erb</code> 的文件,执行其中的代码,然后把结果插入视图。<sup>[<a id="fn-ref-9" href="#fn-9">9</a>]</sup>(回顾一下,执行 Ruby 表达式并将结果插入模板中要使用 <code><%= … %></code>。)注意,文件名 <code>_shim.html.erb</code> 的开头是个下划线,这是局部视图的命名约定,可以在目录中快速定位所有局部视图。</p>
<p>当然,若要局部视图起作用,我们要写入相应的内容。HTML shim 局部视图只包含三行代码,如<a href="#listing-stylesheets-partial">代码清单 5.9</a> 所示。</p>
<div id="listing-stylesheets-partial" data-type="listing">
<h5><span class="title-label">代码清单 5.9</span>:HTML shim 局部视图</h5>
<div class="source-file">app/views/layouts/_shim.html.erb</div>
<div class="highlight language-erb"><pre><span class="x"><!--[if lt IE 9]></span>
<span class="x"> <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js"></span>
<span class="x"> </script></span>
<span class="x"><![endif]--></span>
</pre></div>
</div>
<p>类似地,我们可以把头部的内容移入局部视图,如<a href="#listing-header-partial">代码清单 5.10</a> 所示,然后再次调用 <code>render</code> 把这个局部视图插入布局中。(一般都要在文本编辑器中手动创建局部视图对应的文件。)</p>
<div id="listing-header-partial" data-type="listing">
<h5><span class="title-label">代码清单 5.10</span>:网站头部的局部视图</h5>
<div class="source-file">app/views/layouts/_header.html.erb</div>
<div class="highlight language-erb"><pre><span class="x"><header class="navbar navbar-fixed-top navbar-inverse"></span>
<span class="x"> <div class="container"></span>
<span class="x"> </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="nb">id</span><span class="p">:</span> <span class="s2">"logo"</span> <span class="cp">%></span><span class="x"></span>
<span class="x"> <nav></span>
<span class="x"> <ul class="nav navbar-nav navbar-right"></span>
<span class="x"> <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="x"></li></span>
<span class="x"> <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="x"></li></span>
<span class="x"> <li></span><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s2">"Log in"</span><span class="p">,</span> <span class="s1">'#'</span> <span class="cp">%></span><span class="x"></li></span>
<span class="x"> </ul></span>
<span class="x"> </nav></span>
<span class="x"> </div></span>
<span class="x"></header></span>
</pre></div>
</div>
<p>现在我们已经知道怎么创建局部视图了,让我们来加入和头部对应的网站底部吧。你或许已经猜到了,我们会把这个局部视图命名为 <code>_footer.html.erb</code>,放在布局文件夹中,如<a href="#listing-footer-partial">代码清单 5.11</a> 所示。<sup>[<a id="fn-ref-10" href="#fn-10">10</a>]</sup></p>
<div id="listing-footer-partial" data-type="listing">
<h5><span class="title-label">代码清单 5.11</span>:网站底部的局部视图</h5>
<div class="source-file">app/views/layouts/_footer.html.erb</div>
<div class="highlight language-erb"><pre><span class="x"><footer class="footer"></span>
<span class="x"> <small></span>
<span class="x"> The <a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a></span>
<span class="x"> by <a href="http://www.michaelhartl.com/">Michael Hartl</a></span>
<span class="x"> </small></span>
<span class="x"> <nav></span>
<span class="x"> <ul></span>
<span class="x"> <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="x"></li></span>
<span class="x"> <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="x"></li></span>
<span class="x"> <li><a href="http://news.railstutorial.org/">News</a></li></span>
<span class="x"> </ul></span>
<span class="x"> </nav></span>
<span class="x"></footer></span>
</pre></div>
</div>
<p>和头部类似,在底部我们使用 <code>link_to</code> 创建到“关于”页面和“联系”页面的链接,地址先使用占位符 <code>#</code>。(和 <code>header</code> 一样,<code>footer</code> 也是 HTML5 新增加的标签。)</p>
<p>按照 HTML shim 和头部局部视图的方式,我们也可以在布局视图中渲染底部局部视图,如<a href="#listing-layout-with-footer">代码清单 5.12</a> 所示。</p>
<div id="listing-layout-with-footer" data-type="listing">
<h5><span class="title-label">代码清单 5.12</span>:添加底部局部视图后的网站布局</h5>
<div class="source-file">app/views/layouts/application.html.erb</div>
<div class="highlight language-erb"><pre><span class="x"><!DOCTYPE html></span>
<span class="x"><html></span>
<span class="x"> <head></span>
<span class="x"> <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="x"></title></span>
<span class="x"> </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="p">:</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="x"></span>
<span class="x"> </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="x"></span>
<span class="x"> </span><span class="cp"><%=</span> <span class="n">csrf_meta_tags</span> <span class="cp">%></span><span class="x"></span>
<span class="x"> </span><span class="cp"><%=</span> <span class="n">render</span> <span class="s1">'layouts/shim'</span> <span class="cp">%></span><span class="x"></span>
<span class="x"> </head></span>
<span class="x"> <body></span>
<span class="x"> </span><span class="cp"><%=</span> <span class="n">render</span> <span class="s1">'layouts/header'</span> <span class="cp">%></span><span class="x"></span>
<span class="x"> <div class="container"></span>
<span class="x"> </span><span class="cp"><%=</span> <span class="k">yield</span> <span class="cp">%></span><span class="x"></span>
<span class="hll"><span class="x"> </span><span class="cp"><%=</span> <span class="n">render</span> <span class="s1">'layouts/footer'</span> <span class="cp">%></span><span class="x"></span>
</span><span class="x"> </div></span>
<span class="x"> </body></span>
<span class="x"></html></span>
</pre></div>
</div>
<p>当然,如果没有样式的话,底部还很丑。底部的样式参见<a href="#listing-footer-css">代码清单 5.13</a>,效果如<a href="#fig-site-with-footer">图 5.7</a> 所示。</p>
<div id="fig-site-with-footer" class="figure"><img src="images/chapter5/site_with_footer_bootstrap_3rd_edition.png" alt="site with footer bootstrap 3rd edition" /><div class="figcaption"><span class="title-label">图 5.7</span>:添加底部后的首页</div></div>
<div id="listing-footer-css" data-type="listing">
<h5><span class="title-label">代码清单 5.13</span>:添加网站底部的 CSS</h5>
<div class="source-file">app/assets/stylesheets/custom.css.scss</div>
<div class="highlight language-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="na">margin-top</span><span class="o">:</span> <span class="mi">45</span><span class="kt">px</span><span class="p">;</span>
<span class="na">padding-top</span><span class="o">:</span> <span class="mi">5</span><span class="kt">px</span><span class="p">;</span>
<span class="na">border-top</span><span class="o">:</span> <span class="mi">1</span><span class="kt">px</span> <span class="no">solid</span> <span class="mh">#eaeaea</span><span class="p">;</span>
<span class="na">color</span><span class="o">:</span> <span class="mh">#777</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="na">color</span><span class="o">:</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="na">color</span><span class="o">:</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="na">float</span><span class="o">:</span> <span class="no">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="na">float</span><span class="o">:</span> <span class="no">right</span><span class="p">;</span>
<span class="na">list-style</span><span class="o">:</span> <span class="no">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="na">float</span><span class="o">:</span> <span class="no">left</span><span class="p">;</span>
<span class="na">margin-left</span><span class="o">:</span> <span class="mi">15</span><span class="kt">px</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
</section>
</section>
<section data-type="sect1" id="sass-and-the-asset-pipeline">
<h1><span class="title-label">5.2</span> Sass 和 Asset Pipeline</h1>
<p>在新版 Rails 中,最大的变化是增加了 Asset Pipeline,这个功能明显提升了 CSS、JavaScript 和图片等静态资源文件的生成效率,而且还能降低管理成本。本节我们先大致介绍一下 Asset Pipeline,然后说明如何使用强大的 CSS 编写工具 Sass。</p>
<section data-type="sect2" id="the-asset-pipeline">
<h2><span class="title-label">5.2.1</span> Asset Pipeline</h2>
<p>Asset Pipeline 对 Rails 做了很多改动,但对 Rails 开发者来说只有三个特性需要了解:静态资源文件夹,清单文件,以及预处理器引擎。<sup>[<a id="fn-ref-11" href="#fn-11">11</a>]</sup>下面一一介绍。</p>
<section data-type="sect3" id="asset-directories">
<h3>静态资源文件夹</h3>
<p>在 Rails 3.0 及之前的版本,静态文件放在 <code>public/</code> 文件夹中,并且按照下面的方式组织:</p>
<ul>
<li>
<p><code>public/stylesheets</code></p>
</li>
<li>
<p><code>public/javascripts</code></p>
</li>
<li>
<p><code>public/images</code></p>
</li>
</ul>
<p>这些文件夹中的文件通过请求 <a href="http://example.com/stylesheets" class="bare">http://example.com/stylesheets</a> 等地址直接发送给浏览器。(Rails 3.0 之后的版本也会这么做。)</p>
<p>在最新版 Rails 中,静态文件可以放在三个标准文件夹中,而且各有各的用途:</p>
<ul>
<li>
<p><code>app/assets</code>:当前应用的资源文件;</p>
</li>
<li>
<p><code>lib/assets</code>:开发团队自己开发的代码库使用的资源文件;</p>
</li>
<li>
<p><code>vendor/assets</code>:第三方代码库使用的资源文件;</p>
</li>
</ul>
<p>你可能猜到了,这几个文件夹中都有针对不同资源类型的子文件夹,例如:</p>
<div data-type="listing">
<div class="highlight language-sh"><pre><span class="nv">$ </span>ls app/assets/
images/ javascripts/ stylesheets/
</pre></div>
</div>
<p>现在我们知道 <a href="#bootstrap-and-custom-css">5.1.2 节</a>中 <code>custom.css.scss</code> 存放位置的用意了:因为 <code>custom.css.scss</code> 只在应用中使用,所以把它存放在 <code>app/assets/stylesheets</code> 文件夹中。</p>
</section>
<section data-type="sect3" id="manifest-files">
<h3>清单文件</h3>
<p>把资源文件放在适当的文件夹中之后,要通过清单文件告诉 Rails 怎么把它们合并成一个文件(通过 <a href="https://github.com/sstephenson/sprockets">Sprockets</a> gem 实现,而且只能合并 CSS 和 JavaScript 文件,不会合并图片)。举个例子,我们来看一下应用默认的样式表清单文件,如<a href="#listing-app-css-manifest">代码清单 5.14</a> 所示。</p>
<div id="listing-app-css-manifest" data-type="listing">
<h5><span class="title-label">代码清单 5.14</span>:应用的样式表清单文件</h5>
<div class="source-file">app/assets/stylesheets/application.css</div>
<div class="highlight language-css"><pre><span class="c">/*</span>
<span class="c"> * This is a manifest file that'll be compiled into application.css, which</span>
<span class="c"> * will include all the files listed below.</span>
<span class="c"> *</span>
<span class="c"> * Any CSS and SCSS file within this directory, lib/assets/stylesheets,</span>
<span class="c"> * vendor/assets/stylesheets, or vendor/assets/stylesheets of plugins, if any,</span>
<span class="c"> * can be referenced here using a relative path.</span>
<span class="c"> *</span>
<span class="c"> * You're free to add application-wide styles to this file and they'll appear</span>
<span class="c"> * at the bottom of the compiled file so the styles you add here take</span>
<span class="c"> * precedence over styles defined in any styles defined in the other CSS/SCSS</span>
<span class="c"> * files in this directory. It is generally better to create a new file per</span>
<span class="c"> * style scope.</span>
<span class="c"> *</span>
<span class="hll"><span class="c"> *= require_tree .</span>
</span><span class="hll"><span class="c"> *= require_self</span>
</span><span class="c"> */</span>
</pre></div>
</div>
<p>这里关键的代码是几行 CSS 注释,Sprockets 通过这些注释引入相应的文件:</p>
<div data-type="listing">
<div class="highlight language-css"><pre><span class="c">/*</span>
<span class="c"> .</span>
<span class="c"> .</span>
<span class="c"> .</span>
<span class="c"> *= require_tree .</span>
<span class="c"> *= require_self</span>
<span class="c">*/</span>
</pre></div>
</div>
<p>其中</p>
<div data-type="listing">
<div class="highlight language-text"><pre>*= require_tree .
</pre></div>
</div>
<p>会把 <code>app/assets/stylesheets</code> 文件夹中的所有 CSS 文件(包含子文件夹中的文件)都引入应用的 CSS 。</p>
<p>下面这行:</p>
<div data-type="listing">
<div class="highlight language-text"><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>
</section>
<section data-type="sect3" id="preprocessor-engines">
<h3>预处理器引擎</h3>
<p>准备好资源文件后,Rails 会使用一些预处理器引擎来处理它们,并通过清单文件将其合并,然后发送给浏览器。我们通过扩展名告诉 Rails 使用哪个预处理器。三个最常用的扩展名是:Sass 文件的 <code>.scss</code>,CoffeeScript 文件的 <code>.coffee</code>,ERb 文件的 <code>.erb</code>。我们在 <a href="chapter3.html#layouts-and-embedded-ruby">3.4.3 节</a>介绍过 ERb,<a href="#syntactically-awesome-stylesheets">5.2.2 节</a>会介绍 Sass。本书不会使用 CoffeeScript,这是一个很小巧的语言,可以编译成 JavaScript。(RailsCast 中<a href="http://railscasts.com/episodes/267-coffeescript-basics">关于 CoffeeScript 的视频</a>是很好的入门教程。)</p>
<p>预处理器引擎可以连接在一起使用,因此</p>
<div data-type="listing">
<div class="highlight language-text"><pre>foobar.js.coffee
</pre></div>
</div>
<p>只会使用 CoffeeScript 处理器,而</p>
<div data-type="listing">
<div class="highlight language-text"><pre>foobar.js.erb.coffee
</pre></div>
</div>
<p>会使用 CoffeeScript 和 ERb 处理器(按照扩展名的顺序从右向左处理,所以 CoffeeScript 处理器先执行)。</p>
</section>
<section data-type="sect3" id="efficiency-in-production">
<h3>在生产环境中的效率问题</h3>
<p>Asset Pipeline 带来的好处之一是,能自动优化资源文件,在生产环境中使用效果极佳。CSS 和 JavaScript 的传统组织方式是,把不同功能的代码放在不同的文件中,而且排版良好(有很多缩进)。这么做对编程人员很友好,但在生产环境中使用却效率低下——加载大量的文件会明显增加页面的加载时间,这是影响用户体验最主要的因素之一。使用 Asset Pipeline,生产环境中应用所有的样式都会集中到一个 CSS 文件中(<code>application.css</code>),所有 JavaScript 代码都会集中到一个 JavaScript 文件中(<code>application.js</code>),而且还会压缩这些文件,删除不必要的空格,减小文件大小。这样我们就最好地平衡了两方面的需求,开发方便,线上高效。</p>
</section>
</section>
<section data-type="sect2" id="syntactically-awesome-stylesheets">
<h2><span class="title-label">5.2.2</span> 句法强大的样式表</h2>
<p>Sass 是一种编写 CSS 的语言,从多方面增强了 CSS 的功能。本节我们要介绍两个最主要的功能:嵌套和变量。(还有一个功能是“混入”,<a href="chapter7.html#debug-and-rails-environments">7.1.1 节</a>再介绍。)</p>
<p><a href="#bootstrap-and-custom-css">5.1.2 节</a>说过,Sass 支持一种名为 SCSS 的格式(扩展名为 <code>.scss</code>),这是 CSS 句法的一个扩展集。SCSS 只为 CSS 添加了一些功能,而没有定义全新的句法。<sup>[<a id="fn-ref-12" href="#fn-12">12</a>]</sup>也就是说,所有有效的 CSS 文件都是有效的 SCSS 文件,这对已经定义了样式的项目来说是件好事。在我们的应用中,因为要使用 Bootstrap,所以从一开始就使用了 SCSS。Rails 的 Asset Pipeline 会自动使用 Sass 预处理器处理扩展名为 <code>.scss</code> 的文件,所以 <code>custom.css.scss</code> 文件会首先经由 Sass 预处理器处理,然后引入应用的样式表中,再发送给浏览器。</p>
<section data-type="sect3" id="nesting">
<h3>嵌套</h3>
<p>样式表中经常会定义嵌套元素的样式,例如,在<a href="#listing-universal-css">代码清单 5.5</a> 中,定义了 <code>.center</code> 和 <code>.center h1</code> 两个样式:</p>
<div data-type="listing">
<div class="highlight language-css"><pre><span class="hll"><span class="nc">.center</span> <span class="p">{</span>
</span> <span class="k">text-align</span><span class="o">:</span> <span class="k">center</span><span class="p">;</span>
<span class="p">}</span>
<span class="hll"><span class="nc">.center</span> <span class="nt">h1</span> <span class="p">{</span>
</span> <span class="k">margin-bottom</span><span class="o">:</span> <span class="m">10px</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>使用 Sass 可将其改写成</p>
<div data-type="listing">
<div class="highlight language-scss"><pre><span class="hll"><span class="nc">.center</span> <span class="p">{</span>
</span> <span class="na">text-align</span><span class="o">:</span> <span class="no">center</span><span class="p">;</span>
<span class="hll"> <span class="nt">h1</span> <span class="p">{</span>
</span> <span class="na">margin-bottom</span><span class="o">:</span> <span class="mi">10</span><span class="kt">px</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>嵌套还有一种形式,句法稍有不同。在<a href="#listing-logo-css">代码清单 5.7</a> 中,有如下的代码</p>
<div data-type="listing">
<div class="highlight language-css"><pre><span class="hll"><span class="nf">#logo</span> <span class="p">{</span>
</span> <span class="k">float</span><span class="o">:</span> <span class="k">left</span><span class="p">;</span>
<span class="k">margin-right</span><span class="o">:</span> <span class="m">10px</span><span class="p">;</span>
<span class="k">font-size</span><span class="o">:</span> <span class="m">1.7em</span><span class="p">;</span>
<span class="k">color</span><span class="o">:</span> <span class="m">#fff</span><span class="p">;</span>
<span class="k">text-transform</span><span class="o">:</span> <span class="k">uppercase</span><span class="p">;</span>
<span class="k">letter-spacing</span><span class="o">:</span> <span class="m">-1px</span><span class="p">;</span>
<span class="k">padding-top</span><span class="o">:</span> <span class="m">9px</span><span class="p">;</span>
<span class="k">font-weight</span><span class="o">:</span> <span class="k">bold</span><span class="p">;</span>
<span class="p">}</span>
<span class="hll"><span class="nf">#logo</span><span class="nd">:hover</span> <span class="p">{</span>
</span> <span class="k">color</span><span class="o">:</span> <span class="m">#fff</span><span class="p">;</span>
<span class="k">text-decoration</span><span class="o">:</span> <span class="k">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 data-type="listing">
<div class="highlight language-scss"><pre><span class="hll"><span class="nn">#logo</span> <span class="p">{</span>
</span> <span class="na">float</span><span class="o">:</span> <span class="no">left</span><span class="p">;</span>
<span class="na">margin-right</span><span class="o">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
<span class="na">font-size</span><span class="o">:</span> <span class="mi">1</span><span class="mf">.7</span><span class="kt">em</span><span class="p">;</span>
<span class="na">color</span><span class="o">:</span> <span class="mh">#fff</span><span class="p">;</span>
<span class="na">text-transform</span><span class="o">:</span> <span class="no">uppercase</span><span class="p">;</span>
<span class="na">letter-spacing</span><span class="o">:</span> <span class="mi">-1</span><span class="kt">px</span><span class="p">;</span>
<span class="na">padding-top</span><span class="o">:</span> <span class="mi">9</span><span class="kt">px</span><span class="p">;</span>
<span class="na">font-weight</span><span class="o">:</span> <span class="no">bold</span><span class="p">;</span>
<span class="hll"> <span class="k">&</span><span class="nd">:hover</span> <span class="p">{</span>
</span> <span class="na">color</span><span class="o">:</span> <span class="mh">#fff</span><span class="p">;</span>
<span class="na">text-decoration</span><span class="o">:</span> <span class="no">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>这两种嵌套方式都可以用在<a href="#listing-footer-css">代码清单 5.13</a> 中的底部样式上,改写成:</p>
<div data-type="listing">
<div class="highlight language-scss"><pre><span class="nt">footer</span> <span class="p">{</span>
<span class="na">margin-top</span><span class="o">:</span> <span class="mi">45</span><span class="kt">px</span><span class="p">;</span>
<span class="na">padding-top</span><span class="o">:</span> <span class="mi">5</span><span class="kt">px</span><span class="p">;</span>
<span class="na">border-top</span><span class="o">:</span> <span class="mi">1</span><span class="kt">px</span> <span class="no">solid</span> <span class="mh">#eaeaea</span><span class="p">;</span>
<span class="na">color</span><span class="o">:</span> <span class="mh">#777</span><span class="p">;</span>
<span class="nt">a</span> <span class="p">{</span>
<span class="na">color</span><span class="o">:</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="na">color</span><span class="o">:</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="na">float</span><span class="o">:</span> <span class="no">left</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">ul</span> <span class="p">{</span>
<span class="na">float</span><span class="o">:</span> <span class="no">right</span><span class="p">;</span>
<span class="na">list-style</span><span class="o">:</span> <span class="no">none</span><span class="p">;</span>
<span class="nt">li</span> <span class="p">{</span>
<span class="na">float</span><span class="o">:</span> <span class="no">left</span><span class="p">;</span>
<span class="na">margin-left</span><span class="o">:</span> <span class="mi">15</span><span class="kt">px</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>自己动手改写<a href="#listing-footer-css">代码清单 5.13</a> 是个不错的练习,改完后应该验证一下 CSS 是否还能正常使用。</p>
</section>
<section data-type="sect3" id="variables">
<h3>变量</h3>
<p>Sass 允许我们自定义变量来避免重复,这样也可以写出更具表现力的代码。例如,<a href="#listing-typography-css">代码清单 5.6</a> 和<a href="#listing-footer-css">代码清单 5.13</a> 中都重复使用了同一个颜色代码:</p>
<div data-type="listing">
<div class="highlight language-scss"><pre><span class="nt">h2</span> <span class="p">{</span>
<span class="na">.</span>
<span class="na">.</span>
<span class="na">.</span>
<span class="hll"> <span class="na">color</span><span class="o">:</span> <span class="mh">#777</span><span class="p">;</span>
</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="na">.</span>
<span class="na">.</span>
<span class="na">.</span>
<span class="hll"> <span class="na">color</span><span class="o">:</span> <span class="mh">#777</span><span class="p">;</span>
</span><span class="p">}</span>
</pre></div>
</div>
<p>上面代码中的 <code>#777</code> 是淡灰色,我们可以把它定义成一个变量:</p>
<div data-type="listing">
<div class="highlight language-scss"><pre><span class="nv">$light-gray</span><span class="o">:</span> <span class="mh">#777</span><span class="p">;</span>
</pre></div>
</div>
<p>然后我们可以这样写 SCSS:</p>
<div data-type="listing">
<div class="highlight language-scss"><pre><span class="nv">$light-gray</span><span class="o">:</span> <span class="mh">#777</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="na">.</span>
<span class="na">.</span>
<span class="na">.</span>
<span class="na">color</span><span class="o">:</span> <span class="nv">$light-gray</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="na">.</span>
<span class="na">.</span>
<span class="na">.</span>
<span class="na">color</span><span class="o">:</span> <span class="nv">$light-gray</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>因为像 <code>$light-gray</code> 这样的变量名比 <code>#777</code> 意思更明确,所以把不重复使用的值定义成变量往往也是很有用的。其实,Bootstrap 框架定义了很多颜色变量,<a href="http://getbootstrap.com/customize/#less-variables">Bootstrap 文档中有这些变量的 Less 形式</a>。这个页面中的变量使用 Less 句法,而不是 Sass,不过 <code>bootstrap-sass</code> gem 为我们提供了对应的 Sass 形式。二者之间的对应关系也不难猜测,Less 使用 <code>@</code> 符号定义变量,而 Sass 使用 <code>$</code> 符号。在 Bootstrap 文档中我们看到已经为淡灰色定义了变量:</p>
<div data-type="listing">
<div class="highlight language-text"><pre>@gray-light: #777;
</pre></div>
</div>
<p>也就是说,在 <code>bootstrap-sass</code> gem 中有一个对应的 SCSS 变量 <code>$gray-light</code>。我们可以用它换掉自己定义的 <code>$light-gray</code> 变量:</p>
<div data-type="listing">
<div class="highlight language-scss"><pre><span class="nt">h2</span> <span class="p">{</span>
<span class="na">.</span>
<span class="na">.</span>
<span class="na">.</span>
<span class="na">color</span><span class="o">:</span> <span class="nv">$gray-light</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="na">.</span>
<span class="na">.</span>
<span class="na">.</span>
<span class="na">color</span><span class="o">:</span> <span class="nv">$gray-light</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>使用 Sass 提供的嵌套和变量功能改写应用的整个样式表后得到的代码如<a href="#listing-refactored-scss">代码清单 5.15</a> 所示。这段代码使用了 Sass 变量(参照 Bootstrap Less 变量页面)和内置的颜色名称(例如,<code>white</code> 代表 <code>#fff</code>)。特别注意一下 <code>footer</code> 标签样式的明显改进。</p>
<div id="listing-refactored-scss" data-type="listing">
<h5><span class="title-label">代码清单 5.15</span>:使用嵌套和变量改写后的 SCSS 文件</h5>
<div class="source-file">app/assets/stylesheets/custom.css.scss</div>
<div class="highlight language-scss"><pre><span class="k">@import</span> <span class="s2">"bootstrap-sprockets"</span><span class="p">;</span>
<span class="k">@import</span> <span class="s2">"bootstrap"</span><span class="p">;</span>
<span class="cm">/* mixins, variables, etc. */</span>
<span class="nv">$gray-medium-light</span><span class="o">:</span> <span class="mh">#eaeaea</span><span class="p">;</span>
<span class="cm">/* universal */</span>
<span class="nt">body</span> <span class="p">{</span>
<span class="na">padding-top</span><span class="o">:</span> <span class="mi">60</span><span class="kt">px</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">section</span> <span class="p">{</span>
<span class="na">overflow</span><span class="o">:</span> <span class="no">auto</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">textarea</span> <span class="p">{</span>
<span class="na">resize</span><span class="o">:</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="na">text-align</span><span class="o">:</span> <span class="no">center</span><span class="p">;</span>
<span class="nt">h1</span> <span class="p">{</span>
<span class="na">margin-bottom</span><span class="o">:</span> <span class="mi">10</span><span class="kt">px</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="na">line-height</span><span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">h1</span> <span class="p">{</span>
<span class="na">font-size</span><span class="o">:</span> <span class="mi">3</span><span class="kt">em</span><span class="p">;</span>
<span class="na">letter-spacing</span><span class="o">:</span> <span class="mi">-2</span><span class="kt">px</span><span class="p">;</span>
<span class="na">margin-bottom</span><span class="o">:</span> <span class="mi">30</span><span class="kt">px</span><span class="p">;</span>
<span class="na">text-align</span><span class="o">:</span> <span class="no">center</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">h2</span> <span class="p">{</span>
<span class="na">font-size</span><span class="o">:</span> <span class="mi">1</span><span class="mf">.2</span><span class="kt">em</span><span class="p">;</span>
<span class="na">letter-spacing</span><span class="o">:</span> <span class="mi">-1</span><span class="kt">px</span><span class="p">;</span>
<span class="na">margin-bottom</span><span class="o">:</span> <span class="mi">30</span><span class="kt">px</span><span class="p">;</span>
<span class="na">text-align</span><span class="o">:</span> <span class="no">center</span><span class="p">;</span>
<span class="na">font-weight</span><span class="o">:</span> <span class="no">normal</span><span class="p">;</span>
<span class="na">color</span><span class="o">:</span> <span class="nv">$gray-light</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">p</span> <span class="p">{</span>
<span class="na">font-size</span><span class="o">:</span> <span class="mi">1</span><span class="mf">.1</span><span class="kt">em</span><span class="p">;</span>
<span class="na">line-height</span><span class="o">:</span> <span class="mi">1</span><span class="mf">.7</span><span class="kt">em</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="na">float</span><span class="o">:</span> <span class="no">left</span><span class="p">;</span>
<span class="na">margin-right</span><span class="o">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
<span class="na">font-size</span><span class="o">:</span> <span class="mi">1</span><span class="mf">.7</span><span class="kt">em</span><span class="p">;</span>
<span class="na">color</span><span class="o">:</span> <span class="nb">white</span><span class="p">;</span>
<span class="na">text-transform</span><span class="o">:</span> <span class="no">uppercase</span><span class="p">;</span>
<span class="na">letter-spacing</span><span class="o">:</span> <span class="mi">-1</span><span class="kt">px</span><span class="p">;</span>
<span class="na">padding-top</span><span class="o">:</span> <span class="mi">9</span><span class="kt">px</span><span class="p">;</span>
<span class="na">font-weight</span><span class="o">:</span> <span class="no">bold</span><span class="p">;</span>
<span class="k">&</span><span class="nd">:hover</span> <span class="p">{</span>
<span class="na">color</span><span class="o">:</span> <span class="nb">white</span><span class="p">;</span>
<span class="na">text-decoration</span><span class="o">:</span> <span class="no">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="na">margin-top</span><span class="o">:</span> <span class="mi">45</span><span class="kt">px</span><span class="p">;</span>
<span class="na">padding-top</span><span class="o">:</span> <span class="mi">5</span><span class="kt">px</span><span class="p">;</span>
<span class="na">border-top</span><span class="o">:</span> <span class="mi">1</span><span class="kt">px</span> <span class="no">solid</span> <span class="nv">$gray-medium-light</span><span class="p">;</span>
<span class="na">color</span><span class="o">:</span> <span class="nv">$gray-light</span><span class="p">;</span>
<span class="nt">a</span> <span class="p">{</span>
<span class="na">color</span><span class="o">:</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="na">color</span><span class="o">:</span> <span class="nv">$gray-darker</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nt">small</span> <span class="p">{</span>
<span class="na">float</span><span class="o">:</span> <span class="no">left</span><span class="p">;</span>
<span class="p">}</span>