over 5 years ago

一兩個禮拜之前因為太累,我回家時忘記把 iPhone 4S 從牛仔褲掏出來。洗完澡之後就恍神直接把髒衣服拿去洗衣機直接洗了。

一兩個小時,等我回神過來之後,要幫手機充電,才發現手機已經躺在洗衣機裡面被洗得亮晶晶了。這還不夠,手機還是在開機狀態進去洗的,跟一般只是掉到馬桶進水的狀況不一樣。

Anyway,朋友建議我拿去 忠孝新生站 3 號出口的 麥克愛愛 碰運氣修看看。傳說中這是一間服務非常棒的水果商,他們也「兼修」iPhone 這樣....

賭賭運拿去麥克愛愛修幾天後,幾天店員回電說檢修後發現主機版、螢幕和無線網路模組都炸光光了。維修費用應該會是 ㊙(遠低於我的預算,反正在一萬以內),不過他想他還是可以幫我修看看。

今天被通知修好了,所以就過去拿了。除了香噴噴(咦?)亮晶晶以外(開玩笑,我都用熊寶貝幫他洗澡了...),手機也跟新的一樣活跳跳的回到我手上了。

感謝 麥克愛愛 幫我修好手機,所以特此寫這一篇文章推薦他們。如果你有蘋果電腦或者是 iPhone 手機的問題,歡迎找他們。服務真的相當專業到位。

電話與聯絡方式在 麥克愛愛的臉書專頁 有,出發之前請先電話預約洽詢。

 
over 5 years ago

關於 Github 被入侵這件事,目前在國外開發圈傳的沸沸揚揚。看來中文圈還沒有消息,我來報導一下到底發生了什麼事好了。順便宣導一下開發 Rails 程式碼需要注意的其中一個觀念..

到底發生了什麼事

Rails 的 master 被某個 hacker 塞上這一段 commit。以證明 Github 是可以被入侵的。

為什麼會發生這件事(糾紛起源)

有個俄羅斯 Hacker : homakov 到 Rails 的 Github issue 頁,report 了一個 issue

聲稱他發現很多「中等程度以下的」Rails 開發者開發任何網站,都沒有在 model 內作上任何 attr_accessible 的防護,這樣會引起很多安全性的問題。

Rails 官方應該設計一個機制強迫大家一定得「使用」attr_accessible

因為寫 code 要塞 attr_accessible 被多數開發者認為是根本是一個「常識」。所以這個 issue 很快就被 Rails core team 關掉了。他的意見是這不是 Rails 的問題,而是開發者的問題。(正常人都會做出這樣的反應)

這個 Hacker 覺得他好心來報告,但是卻被忽視,感到很生氣。

於是!他 Hack 了 Github 證明這件事情是真的。

他不僅利用這個漏洞在 rails/rails 中塞了 commit ,連當初被關掉的 issue ,也用同樣方法打開了。

所以這下就鬧到舉世震驚了!…XDDDDD

為什麼會發生這件事(剖析 Rails )

從 Rails 表單機制談起

Rails 秉持著 Don't Repeat Yourself 的精神,將 Form 表單 Helper 直接與 Model 欄位直接結合,節省不少開發者撰寫表單的時間,是一個很聰明的作法。

<%= form_for @post do |f| %>
  <%= f.text_field :title %>
  <%= f.text_area :content %>
  <%= f.sumbit "Submit" %>
<% end %>

當表單送出後,會被壓縮成一個 params[:post] 這樣的 Hash。controller 裡面透過 massive-assignment 的技巧直接 mapping 進 Model 裡。

class PostController < ApplicationController
  def create
     @post = current_user.posts.build(params[:post])
     if @post.save
       # do something
     else
       # do another thing
     end
  end
end

這是一個自 Rails 誕生以來就有的機制了,十分便手。

有些不了解的 Rails 的其他 Developer 批評這是一個不安全設計,並因此拒絕使用 Rails。欄位暴露在外被人知道,讓他們感到非常不自在。

萬一被人猜到 user 權限是用 user.is_admin 作為 boolean 值,這樣豈不是很危險嗎?在修改個人資訊頁時,假造 DOM 就不是可以把自己提升為 admin 了嗎?

Rails 內建的安全防禦措施

Rails 也不是沒有針對這件事設計出防禦措施,有兩組 model API :attr_accessibleattr_protected。其實也就是 白名單、黑名單設計。

attr_accessible 加在 model 裡,可以擋掉所有 massive assignement 傳進來的值,只開放你想讓使用填寫的欄位。

class Post < ActiveRecord::Base
  attr_accessible :title, :content
end

attr_protected 是完全相反地機制。

知名認證 Plugin 皆內建 attr_accessible

也因為 user.is_admin 幾乎是所有懶惰開發者會寫出來的 code。因此長久的歷史演變下來,許多知名認證 plugin,如 devise ,restful-authentication 等等…,在 User model 裡都會加上 attr_accessible(你可能沒有察覺到,因為可能是透過 include Module 塞進來的功能)。

因為是隱藏的內建防禦,很多不夠經驗的開發者,反而會被這道自動防禦整到,在設計修改使用者資訊這個功能時,常常表單明明沒問題,但就是修改不了除了密碼和 email 以外的欄位 XDDD

User model 自動防禦,那其他 model 呢?

好問題!這就是這次 Github 發生的問題。嚴格來說,根本不是 rails/rails 的錯,而是 Github 內某個被罵 mid/junior level 的 developer 的錯。他根本沒有對其他 model 作上保護,才被 hacker 有機可趁。

Hacker 也是想要證明連 Github 都會犯這種錯,才會鬧出這種事件

看到 Github 的事件,我該做什麼?

請回家讀這兩組 model API :attr_accessibleattr_protected 的作用。

並檢查你的 project 內是否有類似問題:一般來說,容易被攻擊的點都跟 relation 比較有關係。也就是 xxxxx_id 的部分都要清查。

Scoped Mass Assignment

這是 Rails 3.1 加入的新 feature : scoped mass assignment,
http://enlightsolutions.com/articles/whats-new-in-edge-scoped-mass-assignment-in-rails-3-1

我也建議你閱讀。

Rails core team 目前的解法

大師 Yahuda Katz (wycats) 目前起草了一份新的 proposal,並且丟在 Hacker News 讓鄉民討論。應該可能近期就會近 Rails core 或以 plugin 的方式釋出。

我個人的感想

其實昨晚睡前看到一堆人說 Github 被 Hacked 掉,然後追了幾篇討論串之後,覺得真的是沒什麼,因為就我來說,的確應該就是這個 hacker 覺得有必要提醒大家,但這對多數的 Rails Developer 來說,根本是超小的小事,不值得這麼大驚小怪。

結果憤怒的 Hacker 攻擊了 Github,Github 真的還因為某個 developer 犯了低級錯誤中招。但我還是覺得沒什麼…

XSS V.S. Massive Assignment

後來睡醒以後才發現不對,其實這東西應該要被拿來跟 auto escape 相比:XSS 是一般設計 Web Application 最容易中招的攻擊。

XSS 的原因肇因是讓開發者開放讓使用者自行輸入內容,然後無保護的讀出來,Hacker 會利用這種漏洞,寫進有害的 JavaScript 讓使用者中招。正確的方式應該是:內容讀出來之後,都要利用 html_escape 濾掉。

問題是,html_escape 濾不勝濾,沒有開發者能夠那麼神,寫任何一段 code 都會自律的加上 h(content)。最後 Rails core 痛定思痛,在 Rails 3.0 後效法 Django 的設計,在讀出 content 時,一律先 escape。除非有必要,才另行設定不需 escape。

我想這次的 massive assignment 問題應該也要比照辦理才對…

延伸閱讀:

國外鄉民懶人包:GitHub and Rails: You have let us all down.

DHH 給出的 37Signals 的作法:https://gist.github.com/1975644

 
over 5 years ago

我創業了。從 2012/03/01 開始,我跟我的好友:國內頂尖的視覺設計師 @evenwu 合組了一間新公司 RocoDev

我們專營:

  • Ruby on Rails Web Application 設計
  • HTML5 / Responsive Design 視覺與網頁設計
  • 網站體質優化 ( SEO / HTML5 semantic / Alexa ranking)

有興趣的朋友可以歡迎找我們洽談服務。

至於我創業的原因,寫在這裡:「我為什麼想創業」。

這也是我另外的一個小部落格,我對於人生的感觸和一些沒有那麼硬的短文會放在這裡。

 
over 5 years ago

有些人問我平常日常怎麼補充知識,所以稍微整理一下我平常看的一些東西分享出來。我平常蠻常到處亂看東西,比例大概是這樣:70% 以上是 Ruby,30 % 是 JavaScript 和其他東西…

不過看完之後當然還要練習,東西才會變自己的就是了...

PODCAST

Screencast

Weekly issue

 
over 5 years ago

昨天在 Happy Designer 5 上,有聊起了做 Responsive Web Design (特別是 mobile 版)的一些狀況。在這裡我提供一些自己的經驗和技巧:

  1. Mobile First:如果你要做 Desktop / Mobile 雙版本的網站。先設計 Mobile 版的,而且要從最小的尺寸開始做。

  2. 盡量讓 Mobile 的版本:大部分功能保持唯讀狀態。因為在 Mobile 上要將「輸入」這件事做得好,是很困難的,而且不少的寫入會牽涉到動線及頁面的跳轉,會大幅降低 user experience。雖然某些功能和元素幹掉很可惜,但要懂得「取捨」。

  3. 不要過於迷信 Media Query: media query 只能解決 CSS 的問題。但是 mobile client 上需要解決的問題不只是這些:

  • 內圖的尺寸與傳輸速度:圖可能是用 Desktop version 的圖硬縮的。
  • 3rd party social plugin:3rd party social plugin 多半沒有考慮 mobile 版本的問題。所以在 mobile 版面上,幾乎都會有尺寸問題。而這些 social plugin 的 js 因為都是由放置在外國的原站提供,在 mobile 版上 loading 更加的緩慢。

所以我會採取「偵測 agent 」與 media query 混合使用的招數進行開發。如果這個 agent 確定是手機,則直接移除掉 social 功能(直接從 server side 幹掉 DOM,而不是用 CSS 隱藏),並且吐尺寸較小的圖片。

  1. 我個人還是認為 Responsive 的用途比較適合用在 Tablet 的 Portrait / Landscape 的用途上。畢竟 Responsive Web Design 的想法,是讓 Desktop / Mobile 擠在同一個版面上,用同一份 code。再 conditional override 或者 remove。在需要「持續維護」的產品上,容易搞死 Developer…

P.S. 如果你對 Responsive Web Design 好奇,可以用手機打開 T 客邦 以及 Digiphoto ,這個站都是用此技巧設計的…

===

廣告:二月份 xdite 家桌遊團 又開放了,限八人,請儘速報名。

 
over 5 years ago

I had a ruby project named "bootstrap_helper", which has 43 watchers on Github.

螢幕快照 2012-02-09 下午4.09.51

I thought having 43 watchers is sort of popular. But there is a weired thing: when I search keyword : "bootstrap helper", my gem is not in first page result.

螢幕快照 2012-02-09 下午3.59.56

Then I found I made a hugh mistake: Ruby naming convention told Ruby developer to name everything with underscore. So every developer names their projects with underscore.

But it's a giant SEO mistake: Search Engine treats snake_keywords as CamelKeywords. If your project's name contains meaningful keywords, it won't be matched. Because "snake_keywords" means "SnakeKeyword" not "snake keywords".

It's really bad for SEO.

 
over 5 years ago

Twitter 的 Bootstrap 是一套很好用的 CSS Framework。可以讓開發者加上工具類 CSS 如 .btn,就設計出一個按鈕。

但有時候這東西也像 inline style 一樣討厭,比如說我要設計一排「按鈕] link,就非得每行都加個 class = "btn"

<div class="job-options">
  <span class="option-title"> 工作類別: </span>
  <%= link_to("網站設計師", jobs_path+"?m_type=1", :class=>"btn ") %>
  <%= link_to("美術設計師", jobs_path+"?m_type=2", :class=>"btn ") %>
  <%= link_to("手機APP開發", jobs_path+"?m_type=3", :class=>"btn ") %>
  <%= link_to("市場行銷", jobs_path+"?m_type=4", :class=>"btn ") %>
  <%= link_to("社群管理", jobs_path+"?m_type=5", :class=>"btn ") %>
  <%= link_to("其他", jobs_path+"?m_type=0", :class=>"btn ") %>
</div>

我在開發時並不是使用 Twitter 自己提供的 LESS 版本,而是採用人家拆好的 SCSS 版本 anjlab/bootstrap-rails

如何翻修這樣的 code 呢?我使用了 SCSS 的 @extend。

.job-options{
   padding-bottom: 10px;
   a{
      @extend .btn;
   }
}
<div class="job-options">
  <span class="option-title"> 工作類別: </span>
  <%= link_to("網站設計師", jobs_path+"?m_type=1") %>
  <%= link_to("美術設計師", jobs_path+"?m_type=2") %>
  <%= link_to("手機APP開發", jobs_path+"?m_type=3") %>
  <%= link_to("市場行銷", jobs_path+"?m_type=4") %>
  <%= link_to("社群管理", jobs_path+"?m_type=5") %>
  <%= link_to("其他", jobs_path+"?m_type=0") %>
</div>

這樣就可以把 .btn 從 HTML 裡面拿掉了。

其他

其實表格也可以比較辦理...

#feeds-list{
   @extend .zebra-striped;
}

====

不過不能 span2 這種定位的 class 不能 @extend。@extend bootstrap 這招只能用在與「位置」無關的 style 上。

 
over 5 years ago

在 Rails 開發中,有時候我們會遇到要在表單中設計 select 的選項。select 吃的 collection 是個 Array 。通常我們會往往第一直覺的想法是將之塞到 model 的 CONSTANT 裡,再寫一個 class method 包裝起來,再寫自己的 collection Helper 叫出來。

<%
def my_collection_select(title, target_id, default_val, objs)
  html = '<div class="clearfix"><label for="normalSelect">'+title+'</label><div class="input">'
  html += '<select name="'+target_id+'" id="normalSelect">'
  objs.each do |obj|
    selected = (default_val.to_s == obj[:downcase].to_s) ? 'selected="selected"' : ''
    html += '<option '+selected+'value="'+obj[:downcase].to_s+'">'+obj[:titleize]+'</option>'
  end 
  html += '</select></div></div>'
  return raw(html)
end

%>

<%= my_collection_select("職務類別", "job[job_category]", @job.job_category, Job.categories) %>
class Job < ActiveRecord::Base
#職務類別


CAT_OTHER                   = 0   #其他

CAT_WEB_DEVLOPER            = 1   #網站設計師

CAT_DESIGNER                = 2   #美術設計師

CAT_PHONE_APP_DEVLOPER      = 3   #手機APP開發

CAT_MARKETING_SALES         = 4   #市場規劃 & 業務

CAT_WEB_SOCIAL_MANAGER      = 5   #社群管理


def self.categories
  [
      {:downcase=>CAT_OTHER, :titleize=>'其他職缺'},
      {:downcase=>CAT_WEB_DEVLOPER, :titleize=>'網站設計師'},
      {:downcase=>CAT_DESIGNER, :titleize=>'美術設計師'},
      {:downcase=>CAT_PHONE_APP_DEVLOPER, :titleize=>'手機APP開發'},
      {:downcase=>CAT_MARKETING_SALES, :titleize=>'行銷&業務'},
      {:downcase=>CAT_WEB_SOCIAL_MANAGER, :titleize=>'社群管理'}
  ]
end

def category_str
   Job.categories.each { |item| 
     return item[:titleize] if item[:downcase] == self.job_category 
   }
end

會這樣設計的原因是:通常程式設計師會想要對一個值 assign 一個數字,又想要用一個英文字包裝它,以方便取用。

這樣設計的手法很常見,但其實這樣的設計一聞下來就有「壞味道」。我自己也是思考了這個問題好幾年,換了非常多寫法,直到最近終於想出一個比較好的方式去設計 select。

翻修

我設計出一個比較漂亮的方式去改寫這樣的 code。當中用到了 settings_logicsimple_form 這兩個 gem。

Simple Form

<%= f.input :job_category, :label => "職務類別" do %>
    <%= f.select :job_category, Job.categories %>
<% end %>

SettingsLogic

app/models/job_data.rb
class JobData < Settingslogic
  source "#{Rails.root}/config/job_data.yml"
  namespace Rails.env
end

把數值塞到 settings

config/job_data.yml
defaults: &defaults
   job_categories:
      other : 0
      web_developer: 1
      designer: 2
      app_developer: 3
      marketing_sales: 4
      web_social_manager: 5
development:
  <<: *defaults

test:
  <<: *defaults

production:
  <<: *defaults

Rails 內建的 I18n

config/locals/job.zh-TW.yml
"zh-TW":
   job_categories:
      other : "其他職缺"
      web_developer: "網站設計師"
      designer: "美術設計師"
      app_developer: "手機APP開發"
      marketing_sales: "行銷&業務"
      web_social_manager: "社群管理"

Model : Job

JobData.job_categories 拉出來會是這樣的內容:

{"other"=>0, "web_developer"=>1, "designer"=>2, "app_developer"=>3, "marketing_sales"=>4, "web_social_manager"=>5}

但 select 要吃的是: [["其他職缺", 0],["網站設計師",1]] 這樣的 Array。所以我們再用 map 去對 I18n 求值包裝。

app/modesl/job.rb
class Job < ActiveRecord::Base

  def self.categories
    JobData.job_categories.map{ |k,v| [I18n.t("job_categories.#{k}"),v] }
  end

end

Helper

最後是如何把 category_str 從 model 搬出來。

這樣很明顯是錯的
  • 這應該是 view 要做的事。
  • 應該善用 Ruby 的特性,而不是跑 each 比較拿數值。
def category_str
   Job.categories.each { |item| 
     return item[:titleize] if item[:downcase] == self.job_category 
   }
end
利用 Ruby 的 Hash 的 key,從翻譯檔裡面拿出正確的中文。
app/helpers/job_helper.rb
  def render_job_category(job)
    key = JobData.job_categories.key(job.job_category)
    I18n.t("job_categories.#{key}")
  end

其他

如果以後想拿數值:

可以這樣下:

  • JobData.job_categories[:designer] => 2
  • I18n.t("job_categories.designer") => "美術設計師"
 
over 5 years ago

前幾天 Code School 的 CSS Cross Country 課程釋出了。這一集是我相當期待的一集,整理和澄清了非常多「非常基礎但如果觀念不好」就會搞得一塌糊塗的 CSS 知識。

看完把筆記整理在這裡,不過相較於原網站,我寫的算是非常簡陋的版本。

我相當強烈推薦大家購買回去和練習,相信會對自己的 CSS 掌握能力有高度的提升。

Ch1

Style 生效的位置

  • inline style
  • <head> </head> 裡面
  • external link: 如 link rel="stylesheet" href="style.css"

Selectos

  • Element selector
  • Class selector
  • ID selector
  • Compound selector : h1#header

Advanced Selector

ref: Taming Advanced CSS Selectors

  • #sidebar h2— 0, 1, 0, 1
  • h2.title — 0, 0, 1, 1
  • h2 + p — 0, 0, 0, 2
  • #sidebar p:first-line — 0, 1, 0, 2

cascade order

優先權照

  • external <link>
  • <head>
  • inline style
  • !important
  • 相同的 selector 重複的屬性,後寫的會覆蓋前面的。沒有重複的則會合併。

Float

定義
  • 把元素從傳統的 document flow 中移除,然後浮動掛在指定的邊界上。
  • 其他在 parent 元素的內容會繞著這個 float 的元素排列。
種類
  • float: left
  • float: right
  • float: none
Stacking order
  • 浮動的元素從 parent 的左/右邊界開始排,不夠放的話會找另下一個可以停泊的邊界繼續排
  • 如果浮動的元素高度不同,例如左邊的特別長,旁邊的元素的比他短,則下一個停泊的不會是左邊界,而是會停在左邊元素的右邊。(下一個可以停泊的邊界原則)
floating left & right

同時使用 float:left 與 float:right,寬度夠的話,會分列兩邊。如果寬度不夠,以先 claim 的會是第一排(靠右),後 claim 的會被扔到下一排(靠左)去。

<div>
    <div class="content1"> </div>
    <div class="content2"> </div>
</div>
.content1 {
    float:right;
}
.content2 {
    float:left;
}

Ch2

clearfix

為什麼要使用 cleafix
  • 狀況一:float 元素可能比旁邊的非 float 元素高。(因為 float 沒有高度)所以下一段會黏上來。
  • 狀況二:所有的 children 都是 float。(因為 float 沒有高度)所以 container 看起來會太短。
常用 clearfix 技巧
clear with a subsequent elemet ( 在下面的元素放 clear: both )
  • 但這一招移動 div 順序就會爆炸
  • 背景和邊界不會被展延

失敗!

manual clearing (手動在下面塞一個空的 div,對它下 clear: both)
  • 需要塞一個空的 element
  • 看起來很礙眼
正解技巧 ( self-cleared )
 
.group:before, .group:after { 
   content: "";
   display: table; 
}
.group:after {
   clear: both; 
}
.group { 
   zoom: 1; /* IE6&7 */ 
}
.group 要下在 parent node
<div class="group">
   <div class="float-left"> </div>
   <p> blah </p>
</div>

Inheritance & Specificity

  • 巢狀元素會自動繼承 parent 的 style
  • 可以 override parent 的 style
  • id 比 class 的優先權高
優先權算法

0,0,0,0

  • 第一個數字:inline style
  • 第二個數字:of ID selectors
  • 第三個數字:of class selectors
  • 第四個數字:of element seletors
p { color: #fff; }  # 0,0,0,1
.intro { color: #98c7d4; } # 0,0,1,0
#header { color: #444245; } # 0,1,0,0
<h1 style="color: #000;">Mogul</h1> # 1,0,0,0
p { color: #fff !important; }

越大的可以把祖先蓋掉。

延伸閱讀:[Don’t use ID selectors in CSS]http://screwlewse.com/2010/07/dont-use-id-selectors-in-css/

Ch3

box model

由內往外是

  • content area
  • padding area
  • border area
  • margin area

寬度計算

box width = content width + padding width + border width

overflow

  • visible: the default value, which allows content to extend beyond container boundaries
  • auto: adds a scrollbar as needed when content overflows
  • hidden: hides content that extends beyond the container
  • scroll: adds a scrollbar at all times, even if unneeded

positioning

有四種

  • static
  • relative
  • absolute
  • fixed

定義

  • Elements have a position value of static by default
  • Using a value other than static causes an object to become a positioned element
  • Positioned elements may use the top, left, bottom, and right properties for placement
Relative positioning

Renders in the normal flow, then shifted via positioning properties

Absolute positioning

Takes an element out of the normal flow for manual positioning

定位技巧

parent element 下 relative,內部需要定位的元素下 absolute,就不會超過邊界。

Fixed positioning

Affixes an element to a specific place in the window, where it will stay regardless of scrolling。(在螢幕上永遠保持不動,釘住)

z-index

  • No z-index or equal z-index = overlap determined by placement in DOM (後放的疊在先放的上面)
  • Higher values appear above lower values( z-index 比較大的在比較上面)
  • Elements must be positioned for z-index to take effect. Use relative if you're not interested in moving the object (必須先被「定位」,才能使用 z-index)

延伸閱讀: Understanding CSS z-index

Ch4

整理 CSS code

,
p .content h3{
   color: red;
}
padding/margin 上右下左
.content {
   margin: 15px 10px 0 20px; /* top right bottom left */ }
}

其他綜合
   font: 16px/18px bold italic sans-serif; /* size/line-height weight style family */
   background: #000 url(image.jpg) no-repeat center top; /* color image repeat x-pos y-pos */
   list-style: disc inside none; /* style position image */
   margin or padding: 0 10px 0 10px / 0 10px 0 / 0 10px; /* top right bottom left / top right&left bottom / top&bottom right&left */
   border: 3px solid #ccc; /* width style color */

Display types

block
  • Stretch the full width of their container ( container 有多寬就延伸到多寬)
  • Behave as though there is a line break before and after the element (有斷行效果)
  • Full box model can be manipulatedDisplay Types

Block elements: Tags that are block-level by default: <div>, <p>, <ul>, <ol>, <li> and <h1> through <h6>.

inline
  • Typically found within block-level elements (通常可以在 block 元素裡找到)
  • Only take up the space of the content inside (只有內容的寬度)
  • Do not generate a line break before and after the content (沒有斷行效果)

Tags that are inline by default include <span>, <a>, <em>, <img>

inline-block
  • Same flow as an inline element but behave as a block element (可以玩 box model)

水平置中技巧

Centering a block-level element
  • Define a width, and the element width must be less than that of the parent container
  • margin: 0 auto;

Centering inline and inline-block elements

  • text-align: center

Ch5

margin 重疊問題

多個 margin 疊在一起,會有 margin 重疊問題( margin 會合併計算,取最大的。假設第一個 div margin-bottom: 40px,第二個 div margin-top: 20px。則他們的距離會是 40px ,而不是 60px)。

解決重疊技巧:

Collapsing margins will not occur when one or more block element has:

  • Padding or border
  • Relative or absolute positioning
  • A float left or right

延伸閱讀: Collapsing margins

rest & normalize

Eric Meyer's Reset CSS
Normalize.css

Ch6

Content Image 與 Layout image

  • Content should be marked up as inline images
  • Layout elements should be defined as background images

Image Cropping

<li class="crop">
  <img src="snowboard.jpg" alt="Snowboard" />
</li>

crop {
    height: 300px; 
    width: 400px; 
    overflow: hidden;
}
.crop img {
    height: 300px; 
    width: auto;
}

其實沒有多少好的方法,建議取代方案:

  • Resize images to a square < height and width of all of your images
  • Resize them server-side
  • Provide image-uploading instructions in your CMS

延伸閱讀:Experiments with wide images

Ch7

圖片取代文字技巧

使用 text-indent: -9999px;

.logo {
    background: url(logo.png);
    display: block;
    height: 100px;
    width: 200px;
    text-indent: -9999px;
}

css spirite 技巧

為什麼要使用 CSS spirite

Issues with swapping background images:

  • Adds an extra HTTP request
  • Image is not preloaded (網路不夠快時,hover 感覺畫面會閃一下)

Advantages to the sprite approach:

  • Reduces number of HTTP image requests
  • Removes loading flash / need for preload
使用方法

Multiple images & states:

 .twitter, .github {
     background: url(social.png);
     display: block;
     height: 100px;
     width: 100px;
     text-indent: -9999px;
}
.github {
    background-position: -100px 0;
}
.twitter:hover, .twitter:focus {
   background-position: 0 -100px;
}
.github:hover, .github:focus {
   background-position: -100px -100px;
}

延伸閱讀: Spritecow

Ch8

psuedo class

Allow you to conditionally select an element based on state or position

  • last-child
  • nth-child (an+b)

延伸閱讀:

psuedo element

<article>
   <p>Coffee? Hah! Our cocoa is far better.</p>
   <p>Visit from 4-5 for cocoa happy hour!</p>
</article>
article p:last-child:after {
   content: '\2744';
}

利用 before, after 技巧

取代掉無用 element
<blockquote>
Coffee? Hah! Our cocoa is far better.
<span></span>
</blockquote>

原本是對 blockquote span 下 styling。

改成對 blockquote:before 下 styling。

html 可以砍成

<blockquote>
Coffee? Hah! Our cocoa is far better.
</blockquote>
利用 before, after 實作縮排

延伸閱讀:A Whole Bunch of Amazing Stuff Pseudo Elements Can Do

 
over 5 years ago

在設計需要顏色循環的表格時你會怎麼作?

table

Rails

初入門者

使用兩種不同 HTML class : even 與 odd,上不同的顏色
<% count = 0 %>
<table>
<% @items.each do |item| %>
  <% if count % 2 == 0 %>
    <% css_class = "even "%>
  <% else %>
    <% css_class = "odd" %>
  <% end %>
  <tr class="<%= css_class %>">
    <td>item</td>
  </tr>
  <% count += 1%>
<% end %>
</table>

<% end %>

懂一點 Ruby

Ruby 裡面有 each_with_index,不需要在外部宣告 count
<table>
<% @items.each_with_index do |item, index| %>
  <% if index % 2 == 0 %>
    <% css_class = "even "%>
  <% else %>
    <% css_class = "odd" %>
  <% end %>
  <tr class="<%= css_class %>">
    <td>item</td>
  </tr>
<% end %>
</table>

熟 Rails Helper

Rails 有 cycle 這個 helper,可以做出循環效果
<table>
<% @items.each do |item| %>
  <tr class="<%= cycle("odd", "even") %>">
    <td>item</td>
  </tr>
<% end %>
</table>

熟 CSS

使用 pseudo class 中的 nth-child
<table>
<% @items.each do |item| %>
  <tr>
    <td>item</td>
  </tr>
<% end %>
</table>

用法::nth-child(an+b)

tr:nth-child(2n+1) {
  color: #ccc;
}
tr:nth-child(2n) {
  color: #000;
}

小結

快改用 nth-child,不要繼續在 class 裡面寫 even, odd, one, two, three 了 XD