[CSS]程式碼的顯示區塊

image

一直想有個可以放程式碼的區塊標籤,我理想中的區塊應該要有以下這五個條件,依優先順序排列:

1.無須再動手修改,便可完整呈現原始的程式碼。原先的white space或特殊符號也應該一應俱全,不會莫名其妙消失。

2.要有行號。這很基本,比較長的程式碼若沒有行號,可讀性極低,幾乎與沒有排版的程式碼一樣屬於無字天書那一掛的。

3.可以在程式碼上面作註記或顏色變化。這樣要強調某些部分的時候,也比較方便。

4.讓程式碼中的所有字串依文法作顏色分類。雖然這個要求比較苛刻些,但我們已經都很習慣編輯器幫忙做這件苦事,所以一旦程式碼脫去五顏六色的外衣,一時之間很難去適應,可讀性因此而降低。

5.執行環境盡量單純化。JAVASCRIPT可不用就不用,讓網頁執行起來順暢一點。

要一口氣達成這五個條件,很有難度,所以我們一步步來,能達成幾個就達成幾個。

拜見了網路上幾位前輩的作法,幾乎都是很直觀地採用CSS標籤製作,製作好標籤,然後直接把程式碼包起來。簡單,直覺,擴充性佳,完整支援CSS,作註記就跟加個標籤一樣簡單。不過,背後還是有它的問題存在,因為並沒有與網頁上的其他程式碼作有效的隔閡,所以展示的程式碼若含有<, >, & 與 "等HTML的預設符號,那麼瀏覽器便會很自然地一道解譯,於是問題就產生了,不是程式碼在瀏覽器底下變得殘缺不全,就是瀏覽器直接執行本來要展示的程式碼,很麻煩的。

所以若要直接使用CSS標籤製作的區塊,需先對程式碼做一番修改,把特殊符號代換掉,如<, >, & 與 ".這四個符號,其代換碼分別是&lt;, &gt;, &amp;, 和 &quot;。這麼繁瑣的動作,手動修改當然不可能,網路上已經有現成的轉換程式,可以直接使用。不過在試用後,並不是很完善,有沒有保持原先的格式,white space有沒有替換乾淨,這些都是個問號;我所希望的是程式碼在格式上百分之百保持原貌,又能依關鍵字分別上色,這樣就很理想了,不過好像還沒有看到有類似的服務,改天有時間的話,再針對這個作研究。

而若要實作的話,個人建議把CSS放在<pre>這個標籤底下,因為<pre>可以讓格式固定,如此一來只要處理跳脫符號即可,非常方便。用來顯示非html語言再適合不過了,範例如下:

1.首先,製作上面有標記行號的圖檔。

這是我所能想到最簡單的方法,在圖片上標上行號,然後設成背景圖片,調整一下,與程式碼字型相配合,便可以假亂真。缺點是部分瀏覽器對<textarea>的CSS支援並不完全,測試了IE、FireFox和Opera,只有在IE底下,<textarea>的背景圖片才能跟著捲軸移動,這無疑地限制了很多東西,不過既然是實驗,就將就將就吧。這是我用小畫家做的行號圖檔:
http://skyblade.myweb.hinet.net/code_94.jpg
因為懶惰,只做到第九十四行,以後若還有需要,再作更大的吧。

 

2.在中宣告一個pre的css介面:

pre.codeStyle {
   display: block; /* fixes a strange ie margin bug */
   background-color: #f0f0f0;
   background-image: url(http://abc9070410.myweb.hinet.net/blogger/code_94.jpg);
   background-repeat: no-repeat;
   background-attachment: scroll; /* 可隨捲軸移動 */
   background-position: top left;
  
   border: 1px solid #ccc;
   padding: 2px 0px 0px 29px;
   overflow:auto;
   max-height:2000px; /* 因為行數圖片只做到第九十四行 */
   max-width:588px;   /* 因為blog的寬度就這樣 */  
   line-height: 1.3em;
}

 

3.可以開始使用啦,語法像這樣:

<pre class="codeStyle" >

~這邊放要展示的程式碼~ 

</pre>

以這一段C語言程式碼為例:

#include  
#include  
using namespace std; 

int main() { 
    ifstream fin("data.txt"); 
    if(!fin) { 
        cout << "無法讀取檔案\n"; 
        return 1; 
    } 

    char name[30]; 
    int request, account, score; 

    cout << "輸入選項:" << endl
         << "1) 顯示所有學生與分數" << endl
         << "2) 顯示及格學生與分數" << endl
         << "3) 顯示不及格學生與分數" << endl
         << "4) 離開" << endl;

    while(true) { 
        cout << "\n選項? "; 
        cin >> request; 
        if(request == 4) 
            break; 

        switch(request) { 
            case 1: 
                cout << "\n所有學生與分數:" << endl;
                break; 
            case 2: 
                cout << "\n及格學生與分數:" << endl;
                break; 
            case 3: 
                cout << "\n不及格學生與分數:" << endl;
                break; 
        } 

        fin >> account >> name >> score; 
        while(!fin.eof()) { 
            if((request == 1) || (request == 2 && score >= 60) || 
               (request == 3 && score < 60)) 
                cout << account << "\t" << name << "\t" << score << endl; 

            fin >> account >> name >> score; 
        } 

        fin.clear();  // 重置 eof 
        fin.seekg(0);  // get 指標移至檔案首 
    } 

    fin.close(); 

    return 0; 
}

 

後來我想到的做法是,把程式碼放入<textarea>,然後把<textarea>作專屬的CSS標籤物件,等於是直接把<textarea>當作CSS標籤來使用。這樣做有個好處──凡放在<textarea>與</textarea>之間的東西,瀏覽器完全不會去過問,也就是說程式碼可以直接複製進去,而不用擔心會被瀏覽器的解譯器逮個正著,完全沒有這一條顧慮。(要說顧慮還是有,因為html的階層概念不是很明確,<textarea>如果裡面再放一個<textarea>,則會對應到裡面的</textarea>而提早結束,所以程式碼中若含有</textarea>,需改成&lt/textarea>,瀏覽器才不會誤判)。

而事情往往是一體兩面的,既然瀏覽器不會檢查,那麼放在<textarea> </textarea>之間的程式碼,若想作局部改變,而試圖使用HTML標籤或JAVASCRIPT,完全都是白費工夫;意思是說,放在這裡面的程式碼,只能做CSS的標準化動作,幾乎可以篤定不可能作部分標記或顏色處理。

<textarea>缺乏彈性,若單純只要簡單快速地展示程式碼,那麼這個方法還算不錯,示範如下:

 

1.首先,製作上面有標記行號的圖檔(上面已經有了)。

 

2.在中宣告一個textarea的css介面:

 

3.可以開始使用啦,語法像這樣:

class="codeStyle",呼叫上面的CSS物件;至於加入WRAP=OFF,是為了不讓程式碼自動換行,我試了好久才發現,用它可以避免這種情況。 長寬也可以用CSS的style設置,但rows直接對應行號,好用多了。

以這一小段程式碼為例:

 

以上便是我對程式碼區塊的兩個粗略實作,可以改進的地方還很多,這只算是一個開頭。

 

One response to “[CSS]程式碼的顯示區塊” ;

cgi 提到...

hello 你文章寫得好詳細,想麻煩請教一個問題
我的程式碼引用後會自動產生左右橫向的「捲軸」
不會自動跳行,似乎是Firefox的關係
我希望程式碼可以自動換行,不要產生捲軸
想請問版主知道可以怎麼解決嗎?

謝謝


張貼留言