Python版已停止维护,请关注跨平台的Nodejs版本 https://github.com/wangjeaf/ckstyle-node
Python Other
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
bin
ckstyle
doc
editor-plugins
tests
utils
.gitignore
LICENSE
README.md
ckstyle.ini
go.bat
setup.py

README.md

CSSCheckStyle

Catalog

Description

@description {
	destination: 一个CSS的检查、修复、压缩、分浏览器终极压缩的工具集;
    website: CKstyle官方网站;
    blog: 《CSSCheckStyle——CSS的解析、检查、修复和压缩》;
	reference: 《人人FED CSS编码规范》;
    export-tools: ckstyle(检查check/修复fix/压缩compress)
    docs: https://github.com/wangjeaf/CSSCheckStyle-docs
	language: python;
}

Installation

easy_install https://github.com/wangjeaf/CSSCheckStyle/archive/master.tar.gz

另外,也可以将此压缩包下载到本地,通过 easy_install xxxx.tar.gz完成安装

Editor plugins

目前已经为 VIM / Sublime Text 2 / Notepad ++ 开发了ckstyle插件,可供使用。

不同编辑器实现的命令调用方式如下:

  • VIM(command命令)
  • Sublime Text 2(快捷键Ctrl+F1,右键菜单项,tools菜单项)
  • notepad++(快捷键Ctrl+F1,宏菜单项)
  • EditPlus(工具菜单项,快捷键)

各编辑器插件均实现了以下几种操作:

  • Fixstyle(自动修复CSS代码)
  • FixstyleSafe(安全模式下自动修复CSS代码,目前仅排除合并规则集)
  • FixstyleSingleLine(修复成单行模式)
  • CkStyle(检查代码问题)
  • CssCompress(压缩CSS代码)

所有编辑器插件都在 editor-plugins 目录下。

目前插件的功能还比较初级,热烈欢迎熟悉插件开发的同学来贡献编辑器插件。

如果插件使用过程中出现任何问题,请在github上报bug,或者微博 @wangjeaf

Demo (parse -> fix -> compress)

说明

以下是通过自动fix,自动排序,自动合并,自动压缩以后的代码示例。

结果来自plugins/.py中的fix方法,以及entity/.py的compress方法。

对于fix,目前只做了以下几个plugin的fix:

  • FEDHexColorShouldUpper
  • FEDUseSingleQuotation
  • FEDCombineInToOne (通过combiner的方式灵活扩展,目前只做了MarginCombiner)

其他的fix只需要在对应的plugin文件中添加fix方法,即可实现fix和压缩

此Demo执行的命令: ckstyle compress -p test.css

before

.test1 {
    width: 100px;
    height: 200px;
    *display: none;
    border: 1px solid #FFFFFF;
    _display: inline-block;
    margin: 10px;
    margin-top: 20px;
}

.test2 {
    *display: none;
    width: 100px;
    border: 1px solid #FFF;
    height: 200px;
    _display: inline-block;
    margin: 20px 10px 10px;
}

.test3 {
    margin: 0 10px 20px;
    border: 1px solid #fff;
    width: 100px;
    height: 200px;
    *display: none;
    _display: inline-block;
    margin-top: 20px;
    margin-left: 10px;
    margin-right: 10px;
    margin-bottom: 10px;
}

.test4 {
    border: 1px solid #ffffff;
    *display: none;
    width: 100px;
    height: 200px;
    margin: 10px;
    _display: inline-block;
    margin-top: 20px;
}

.test5 {
    margin: 10px;
    margin-top: 20px;
    width: 100px; *display: none; height: 200px;
    border: 1px solid #ffffff;
    _display: inline-block;
    margin-left: 10px;
}

fixstyle

fixstyle 自动修复以后的代码:

.test1,
.test2,
.test3,
.test4,
.test5 {
    *display: none;
    _display: inline-block;
    width: 100px;
    height: 200px;
    margin: 20px 10px 10px;
    border: 1px solid #FFF;
}

fixstyle --singleLine 自动修复后的代码:

.test1,
.test2,
.test3,
.test4,
.test5 { *display: none; _display: inline-block; width: 100px; height: 200px; margin: 20px 10px 10px; border: 1px solid #FFF; }

after compress

本压缩工具的压缩结果(属性排列顺序已经按照推荐顺序优化),压缩率: 140 / 766 = 18.3%:

.test1,.test2,.test3,.test4,.test5{*display:none;_display:inline-block;width:100px;height:200px;margin:20px 10px 10px;border:1px solid #FFF}

CSS Optimizer 压缩结果,压缩率:310 / 766 = 40.5%:

.test1,.test2,.test3,.test4,.test5{width:100px;height:200px;*display:none;_display:inline-block}.test1,.test3,.test4,.test5{border:1px solid #fff}.test1,.test4,.test5{margin:10px;margin-top:20px}.test2{border:1px solid #FFF}.test2,.test3{margin:20px 10px 10px}.test3{margin:0 10px 20px}.test5{margin-left:10px}

YUI Compressor 压缩结果,压缩率:662 / 766 = 86.4%:

.test1{width:100px;height:200px;*display:none;border:1px solid #fff;_display:inline-block;margin:10px;margin-top:20px}.test2{*display:none;width:100px;border:1px solid #FFF;height:200px;_display:inline-block;margin:20px 10px 10px}.test3{margin:0 10px 20px;border:1px solid #fff;width:100px;height:200px;*display:none;_display:inline-block;margin-top:20px;margin-left:10px;margin-right:10px;margin-bottom:10px}.test4{border:1px solid #fff;*display:none;width:100px;height:200px;margin:10px;_display:inline-block;margin-top:20px}.test5{margin:10px;margin-top:20px;width:100px;*display:none;height:200px;border:1px solid #fff;_display:inline-block;margin-left:10px}

Demo (parse -> check)

此处演示的是代码风格检查功能。

所有的检查项都来自于plugins/*.py的check方法

原始CSS代码

.test1 ul li a {
width:10px;
color:#ffffff;
    -webkit-border-radius:3px;
-moz-border-radius : 3px;
border-radius:3px
}

检查与修改过程

检查结果 1:

[ERROR] 1. use less tag in ".test1 ul li a"
[ERROR] 2. css3 prop "-webkit-border-radius" missing some of "-webkit-,-moz-,-o-,std" in ".test1 ul li a"
[ERROR] 3. css3 prop "-moz-border-radius" missing some of "-webkit-,-moz-,-o-,std" in ".test1 ul li a"
[ERROR] 4. css3 prop "border-radius" missing some of "-webkit-,-moz-,-o-,std" in ".test1 ul li a"
 [WARN] 5. do not simply use 1,2,3 as selector, in ".test1 ul li a"
 [WARN] 6. color should in upper case in ".test1 ul li a"
 [WARN] 7. each rule in ".test1 ul li a" need semicolon in the end, "border-radius" has not
  [LOG] 8. css3 prop "-moz-border-radius" should align to right in ".test1 ul li a"
  [LOG] 9. css3 prop "border-radius" should align to right in ".test1 ul li a"
  [LOG] 10. should have 4 spaces before "width" in ".test1 ul li a"
  [LOG] 11. should have 4 spaces before "color" in ".test1 ul li a"
  [LOG] 12. should have (only) one "space" before value of "-webkit-border-radius" in ".test1 ul li a"
  [LOG] 13. should not have "space" after "-moz-border-radius" in ".test1 ul li a"
  [LOG] 14. should have (only) one "space" before value of "border-radius" in ".test1 ul li a"

第一次修改后:

.test-special-word a.a-class {
    width:10px;
    color:#FFFFFF;
    -webkit-border-radius: 3px;
       -moz-border-radius: 3px;
         -o-border-radius: 3px;
            border-radius: 3px;
}

再次检查:

[ERROR] 1. should not put "HTMLtag" and ".class" together in ".test-special-word a.a-class"
 [WARN] 2. replace "#FFFFFF" with "#FFF" in ".test-special-word a.a-class"
  [LOG] 3. should have (only) one "space" before value of "width" in ".test-special-word a.a-class"
  [LOG] 4. should have (only) one "space" before value of "color" in ".test-special-word a.a-class"

符合规范的最终代码

.test-special-word .a-class {
    width: 10px;
    color: #FFF;
    -webkit-border-radius: 3px;
       -moz-border-radius: 3px;
         -o-border-radius: 3px;
            border-radius: 3px;
}

Usage

关于ckstyle的子命令及命令行参数说明

通过 ckstyle -h / ckstyle --help可以查看命令的帮助,例如: ckstyle compress -h ckstyle compress --help

ckstyle(检查)/fixstyle(自动修复)/compress(压缩,同名工具csscompress) 三个工具的命令行参数基本相同

注意:从 CSSCheckStyle1.1 以后开始,ckstyle的命令调整为子命令模式,即:

  • ckstyle --> ckstyle check

  • fixstyle --> ckstyle fix

  • csscompress --> ckstyle compress

不同之处:

  • fixstyle给出了额外的参数:--fixedExtension(修复后文件的扩展名), --singleLine(自动修复并以单行模式格式化),--safeMode(安全模式,不做某些“本工具不能完全保证正确”的修复)
  • compress给出了额外的参数:--safeMode(安全模式,不做某些“本工具不能完全保证正确”的修复),--browsers(是否分浏览器压缩), --compressExtension(压缩后文件的扩展名), --combineFile(是否将多个压缩后文件合并),这些参数目前有的尚未实现~~~

此外,自 CSSCheckStyle1.1 以后开始,新增如下几个命令:

  • ckstyle install/add/get pluginName 用于从 ckstyle-pm 安装新的规则插件
  • ckstyle uninstall/remove/rm pluginName 用于移除已安装规则插件
  • ckstyle installcmd/addcmd/getcmd commandName 用于从 ckstyle-pm 为ckstyle添加子命令,如 ckstyle demo xxx.css
  • ckstyle uninstallcmd/removecmd/rmcmd commandName 用于移除已安装的子命令

安装的插件将放置在ckstyle/userplugins/plugins目录下

安装的子命令将放置在 ckstyle/userplugins/commands目录下

Examples

ckstyle check                        用默认配置检查当前目录下的所有css文件
ckstyle check -h / ckstyle --help    显示帮助
ckstyle check file.css               检查单个css
ckstyle check dir                    检查目录下的所有css
ckstyle check -r dir                 递归检查目录下的所有css
ckstyle check -p file.css            检查结果打印到控制台,默认是写file.css.ckstyle.txt文件
ckstyle check -r -p dir              同上
ckstyle check -c xxx.ini             使用xxx.ini中的配置进行检查
ckstyle check -c xxx.ini -r -p       使用xxx.ini中的配置进行递归检查,并将结果输出到控制台
ckstyle check -r --extension=.test.txt --include=all --exclude=none --errorLevel=2   使用配置的信息进行检查

ckstyle check -c xxx.ini -r -p --extension=.test.txt --include=all --exclude=none --errorLevel=2 dirpath

CommandLine Options

-h / --help     显示帮助
-r              递归检查所有文件
-p              将结果打印到控制台(同时删除已有的对应的结果文件)
-c / --config   指定配置文件(默认使用~/ckstyle.ini)
--include       指定包含的规则(多个规则请以逗号分隔,例如: rule1,rule2,rule3)
--exclude       指定除外的规则(格式同--include)
--extension     指定扩展名
--errorLevel    指定检查出的异常等级(0-error, 1-warning, 2-log)

// for fix and compress
--fixedExtension 修复后文件的扩展名,如.fixed.css,none为替换原文件(将生成一个.bak文件保存原文件)
--compressExtension 压缩后文件的扩展名,如.min.css,none为替换原文件(将生成一个.bak文件保存原文件)
--safeMode      修复和压缩的安全模式
--singleLine    自动修复成单行模式(默认是多行模式)
--browsers      分浏览器压缩

Config File

可通过以下三个方式来指定配置文件:

  • 命令行通过-c 或 --config来指定配置文件路径
  • 在执行ckstyle命令的当前目录下添加 ckstyle.ini,则默认获取此配置文件
  • 在用户默认目录放入ckstyle.ini

Config File Options

error-level        [=0] 异常等级
include            [=all] 包含的规则
exclude            [=none] 除外的规则
recursive          [=false] 是否递归检查目录下所有文件
print-flag         [=false] 是否打印到控制台
extension          [=.ckstyle.txt] 指定检查结果文件的扩展名
standard           [=standard.css] 给一个标准的css文件,检查时遵照此文件来检查
ignore-rule-sets   [=@unit-test-expecteds] 忽略的一些规则集
fixed-extension    [=.fixed.css] 修复后文件的扩展名
fix-to-single-line [=false] 是否自动修复成一行
safe-mode          [=false] 是否尝试做某些“本工具不能完全保证正确”的修复,true为不尝试,false为尝试

extension(compress)[=.min.css] 压缩后的文件扩展名
combine-file       [=all.min.css] 压缩多个文件合并成一个的文件名
browsers           [=None] 针对不同浏览器生成不同的压缩后文件,使用时如果多个浏览器,需要引号括起来,并用逗号分隔

Config File Demo

[ckstyle]
error-level = 0
include = all
exclude = none
recursive = false
print-flag = false
extension = .ckstyle.txt
standard = standard.css
ignore-rule-sets = @unit-test-expecteds
fixed-extension = .fixed.css
fix-to-single-line = false
safe-mode = false

[compress]
extension = .min.css
combine-file = all.min.css(todo)
browsers = None

[css-format(todo)]
tab-spaces = 4

[global-selectors(todo)]
.nav, sidebar2 = home-frame2.css

[plugin]
plugin-a-prop = 1
plugin-b-prop = 2

Config Priority

配置项的优先级: 命令行参数 > 指定的配置文件 > 当前路径下的配置文件 > 用户目录下的配置文件 > 工具的默认参数

Plugin Development

目前ckstyle官方插件管理已经开启,在这里:ckstyle-pm

大家可以通过ckstyle install/get/add pluginName来安装插件。欢迎贡献插件

放置在ckstyle/plugins目录下的所有文件(Base.py和helper.py除外),每一个文件都对应一种检查规则。

开发时可自行添加和修改,但是必须满足以下条件:

1、文件中必须包含与文件名相同的类名,比如FEDNoExpression.py中包含FEDNoExpression类

2、类必须继承自RuleChecker/RuleSetChecker/StyleSheetChecker

3、类中必须包含check方法,并且传入rule/ruleSet/styleSheet作为参数,并且返回True(通过)/False(不通过)或错误信息数组

4、如果check返回bool值,则类中必须包含errorLevel和errorMsg属性,便于检测异常时给出错误提示

5、errorMsg中可以包含 ${selector}/${name}/${value}等属性设置,在错误提示时将进行相应替换

6、每一个规则,需要在tests目录中添加对应的单元测试用例,测试用例请参见"Unit Test"小节

7、每一个插件,需要按照json格式,编写此类对应的__doc__,以便为官网的此规则生成选项。

8、插件类可以指定一个private属性,如果是private,则不会在官网中生成选项,而且private的类自动必选。

plugin Demo

from Base import *

class FEDSemicolonAfterValue(RuleChecker):
    def __init__(self):
        self.id = 'add-semicolon'
        self.errorLevel = ERROR_LEVEL.WARNING
        self.errorMsg = 'each rule in "${selector}" need semicolon in the end, "${name}" has not'

    def check(self, rule, config):
        if not rule.strippedValue.endswith(';'):
            return False
        return True 

    def fix(self, rule, config):
        pass

Unit Test

每一个规则,都需要添加对应的单元测试

放置在tests/unit目录下的所有文件,都是单元测试用例文件(asserts.py和helper.py除外)

tests/runUnitTests.py是单元测试运行器,将运行tests/unit的所有单元测试并给出运行结果

Python Unit Test

Python单元测试必须:

1、在文件中引入asserts.py,用于断言

2、在文件中加入doTest方法,并在doTest方法及其调用中编写断言

python Unit Test Demo

from asserts import *
from helper import doCssCheck

def doTest():
    text = 'body {width: 1px}'
    logs, warns, errors = doCssCheck(text)
    equal(len(logs), 2, 'two logs')
    equal(len(warns), 1, 'one warn happened')
    equal(len(errors), 1, 'one error happened')
    equal(warns[0], r'each rule in "body" need semicolon in the end, "width" has not', 'warn rule text is ok')
    equal(errors[0], r'should not set style for html tag in "body"', 'error rule text is ok')

Css Unit Test

CSS的单元测试,必须满足以下条件:

1、必须包含@unit-test-expecteds,并在此规则中写入单元测试断言

2、每一个规则由key-value组成,key为错误的errorLevel,value为错误消息

3、如果断言中有,而实际检查结果中没有,测试时将出现[expect but not have]

4、如果断言中没有,而实际检查结果中有,测试时将出现[unexpect but has]

5、一定要注意errorLevel是否正确

CSS Unit Test Demo

@unit-test-expecteds {
    1: zero should be removed when meet 0.xxx in ".test"
    1: zero should be removed when meet 0.xxx in ".test-another"
    1: zero should be removed when meet 0.xxx in ".test-padding"
}

.test {
    width: 0.1px;
}

.test-another {
    width: 0.001px;
}

.test-padding {
    padding: 1px 0.2px;
}

Rules(Plugins)

所有的规则都对应唯一id,并且有独立的检查类,所有的规则类都在ckstyle/plugins一级目录下。

规则id、Python类与检查内容的对应关系(属性名为id,括号内为Python类名)如下:

@all-rules {
    hexadecimal-color:              16进制颜色,大写,并且尽量省略 (FEDHexColorShouldUpper);
    no-font-family:                 不允许业务代码设置字体 (FEDCanNotSetFontFamily);
    combine-into-one:               将可以合并的样式设置合并 (FEDCombineInToOne);
    comment-length:                 注释长度不允许超过80个字符 (FEDCommentLengthLessThan80);
    css3-with-prefix:               css3前缀相关检查 (FEDCss3PropPrefix);
    css3-prop-spaces:               css3缩进相关检查 (FEDCss3PropSpaces);
    no-style-for-simple-selector:   不要为简单选择器设置样式,避免全局覆盖 (FEDDoNotSetStyleForSimpleSelector);
    no-style-for-tag:               不要为html tag设置样式 (FEDDoNotSetStyleForTagOnly);
    font-unit:                      字体的单位必须使用px或pt (FEDFontSizeShouldBePtOrPx);
    hack-prop:                      hack属性时的检查 (FEDHackAttributeInCorrectWay);
    hack-ruleset:                   hack规则时的检查 (FEDHackRuleSetInCorrectWay);
    high-perf-selector:             针对低性能的选择器的检查 (FEDHighPerformanceSelector);
    multi-line-brace:               代码多行时的括号检查 (FEDMultiLineBraces);
    multi-line-selector:            代码多行时的选择器检查 (FEDMultiLineSelectors);
    multi-line-space:               代码多行时的空格检查 (FEDMultiLineSpaces);
    add-author:                     需要在文件中添加作者信息 (FEDMustContainAuthorInfo);
    no-alpha-image-loader:          不要使用alphaImageLoader (FEDNoAlphaImageLoader);
    no-appearance-word-in-selector: 不要在选择器中出现表现相关的词汇 (FEDNoAppearanceNameInSelector);
    no-comment-in-value:            不要在css属性中添加注释 (FEDNoCommentInValues);
    no-empty-ruleset:               删除空的规则 (FEDNoEmptyRuleSet);
    no-expression:                  不要使用非一次性表达式 (FEDNoExpression);
    number-in-selector:             不要在选择器中使用简单数字1、2、3 (FEDNoSimpleNumberInSelector);
    no-star-in-selector:            不要在选择器中使用星号 (FEDNoStarInSelector);
    del-unit-after-zero:            删除0后面的单位 (FEDNoUnitAfterZero);
    no-zero-before-dot:             删除0.2前面的0 (FEDNoZeroBeforeDot);
    no-border-zero:                 用border:none替换border:0 (FEDReplaceBorderZeroWithBorderNone);
    no-underline-in-selector:       不要在选择器中使用下划线 (FEDSelectorNoUnderLine);
    add-semicolon:                  为每一个属性后添加分号 (FEDSemicolonAfterValue);
    do-not-use-important:           不要使用important (FEDShouldNotUseImportant);
    single-line-brace:              单行的括号检查 (FEDSingleLineBraces);
    single-line-selector:           单行的选择器检查 (FEDSingleLineSelector);
    single-line-space:              单行的空格检查 (FEDSingleLineSpaces);
    keep-in-order:                  属性应该按照推荐的顺序编写 (FEDStyleShouldInOrder);
    no-chn-font-family:             不要出现中文的字体设置,改用对应的英文 (FEDTransChnFontFamilyNameIntoEng);
    unknown-css-prop:               错误的css属性 (FEDUnknownCssNameChecker);
    unknown-html-tag:               错误的html tag (FEDUnknownHTMLTagName);
    lowercase-prop:                 属性应该用小写 (FEDUseLowerCaseProp);
    lowercase-selector:             选择器用小写字母 (FEDUseLowerCaseSelector);
    single-quotation:               使用单引号 (FEDUseSingleQuotation);
    z-index-in-range:               z-index取值应该符合范围要求 (FEDZIndexShouldInRange);
    remove-duplicated-attr:         删除重复的属性设置,取后面的(FEDRemoveDuplicatedAttr);
}

Join Us

Email: wangjeaf@gmail.com

Websites: http://www.csscheckstyle.com/ | http://fed.renren.com/ | http://www.renren.com/