CSS | Kayo's Melody https://kayosite.com Practice Makes Perfect Sun, 26 Sep 2021 06:34:38 +0000 zh-CN hourly 1 https://cdn.kayosite.com/wp-content/uploads/2021/08/image.jpg?imageMogr2/thumbnail/!64x64r|imageMogr2/gravity/Center/crop/64x64 CSS | Kayo's Melody https://kayosite.com 32 32 115630942 从 Sass Breaking Change: Slash as Division 说起 https://kayosite.com/analysis-of-sass-breaking-change-slash-as-division.html https://kayosite.com/analysis-of-sass-breaking-change-slash-as-division.html#respond Sun, 26 Sep 2021 06:32:50 +0000 https://kayosite.com/?p=3753 最近在修改一个项目的时候,发现了一系列的 Sass 的告警——由除号引起的告警:

Sass Division 告警

目录

什么告警?

告警的内容很简单,用 / 作为除法已经在 Dart Sass 2.0.0 中被弃用了,作为一个 Sass 的基础语法,这次弃用属于 breaking change 了,因此目前编译时只是会抛出 warning 而不是 error,否则大量项目都无法正常运行。

研究了一下可以看到,Sass 官方特定用了一整个篇幅的文章,来阐述为何要作出这个修改,主要的原因在于,/ 在 Sass 中同时承担除号以及 CSS 分隔符的作用,例如:

Sass 代码

// 作为除号使用
.test_division {
    border-radius: ceil(28px / 2);
}

// 作为 CSS 分隔符使用
.test_operator {
    font: 12px/1.5 -apple-system, "SF UI Text", "PingFang SC", "Lucida Grande", "Microsoft YaHei", sans-serif;
}

实际编译出的 CSS 代码

.test_division {
    border-radius: 14px;
}

.test_operator {
    font: 8px -apple-system, "SF UI Text", "PingFang SC", "Lucida Grande", "Microsoft YaHei", sans-serif;
}

示例中有两个 /,一个是用作除号,另一个是作为 font 属性中 font-sizeline-height 的分隔符,可以看到作为除号使用的时候,/ 一般不会出现什么问题,但是作为分隔符使用的时候,/ 很容易被重载为除号,实际上要实现分隔符的效果,通常需要这样编写:

.test_operator {
    font: #{12px/1.5} -apple-system, "SF UI Text", "PingFang SC", "Lucida Grande", "Microsoft YaHei", sans-serif;
}

使用了插值(Interpolation)语法,包裹了 12px/1.5,插值的作用是仅解析 Sassscript,把 Sass 变量输出为实际的值,但不会进行运算,如果属性值比较复杂,则会导致编写的时候不大直观。

Sass 本身使用了 complex heuristics 的技术去判断 / 应该作为除号还是分隔符,complex heuristics 是需要回顾当前上下文的内容,来作出判定的,因此对于 Sass 来说存在一定消耗。

综合来说,原有的 / 语法对于开发者会带来一些困扰,尤其是随着 CSS 有更多的属性使用到了分隔符(例如 gridhsl() 等语法),同时对于 Sass 的维护以及编译也会带来一些额外的消耗,所以 Sass 最终决定重新定义除法,新的语法也相当清晰:

@use "sass:math";

.test_division {
    border-radius: math.div(28px, 2);
}

新的语法基于 Sass 的 module 语法,引入了相关的运算模块后,就可以调用 math.div 代替原来的 /,而 / 则只作为分隔符使用。

如何解决告警?

要解决告警,首先要知道为何项目中会出现这个告警,用到了这个语法的项目比较多,但目前只有这个项目出现了告警。

首先这个 breaking change 仅在 Dart Sass 的最新版本中才引入,Node Sass 的版本目前还没有跟上。另外该项目中是使用 "sass": "^1.30.0" 来声明 sass 模块的版本(即 Dart Sass 的 npm 包),重新执行 npm i 会导致安装上新版的 Dart Sass 从而出现告警,因此解决方案也围绕 Dart Sass 版本去处理。

降级 sass 模块

删除 package-lock.jsonnode_modules,把 package.json 中 sass 模块的版本改为 "sass": "~1.32.12",即版本号会少于 1.33.0,这个版本的 Dart Sass 并未引入 slash as division 的 breaking change。

更新业务语法

即按上面提到的方式,把相关的告警内容改为用新的 math.div 语法代替,如果涉及的业务量比较大,更新起来会比较费时。

使用 sass-migrator

sass-migrator 是 Sass 官方推出的迁移工具,方便开发者对原有的业务代码进行最新版本的 Sass 适配。sass-migrator 并不是把相关的旧语法直接替换为最新的语法,而且采用更稳固的方式,把代码安全地更新为符合最新要求的语法,例如上面的例子:

Sass 代码

.test_division {
    border-radius: ceil(28px / 2);
}

sass-migrator 的安装与调用

npm i -g sass-migrator
sass-migrator division test.scss

处理后的 Sass 代码

.test_division {
    border-radius: ceil(28px * 0.5);
}

可以看到,sass-migrator 并没有把原有的 / 修改为最新的 math.div 语法,而是修改为用乘法代替。实际上跟 sass 基于 complex heuristics 进行分析会把分隔符重载为除号一样,迁移工具也无法准确地判断每个 / 的作用,因此 sass-migrator 采用了稳固的方式去适配最新的 Sass 规则。

Dart Sass Vs Node Sass

Node Sass 由于没有引入最新的 Sass 特性,因此并不会出现这个告警,但并不建议使用 Node Sass 代替已经用 Dart Sass 编写的代码,主要是:

  • Dart Sass 已经是官方的首选,无论是新特性还是问题修复,Dart Sass 会有更强的时效性,担心新特性会为业务带来问题可以通过锁包进行控制。
  • Node Sass 实际上已经被官方定义为 deprecated,目前项目会维护一个主要版本,但是维护进度并不确定,并且明确没有计划再为 Node Sass 添加新特性,也不会适配 CSS 的新特性。
  • Node Sass 基于 LibSass 开发,而 LibSass 依赖了的模块安装比较麻烦,尤其是对于 Windows 的用户,它要求用户在 Windows 中必须安装 Python2 和 Visual Studio。

因此出于长期维护的考虑,选用 Dart Sass 也是一个趋势。

Dart Sass on Dart-VM 与 Dart Sass on NPM

目前 Dart Sass 有两种实现,分别是:

  • 基于 Dart-VM 的 Dart Sass
  • 基于纯 JavaScript 的 Dart Sass

根据官方的介绍,单独运行的命令行版本,是基于 Dart-VM 运行的,得益于 Dart-VM 的高性能,这个版本的 Dart Sass 性能非常好,适合用于编写脚本单独编译 Sass 文件。

而 NPM 中的 Dart Sass 则是纯 JavaScript 实现,因此可以很方便地用于前端项目构建。虽然 JavaScript 版本的 Dart Sass 性能比 LibSass 要差一些,但是对于样式代码的编译量来说,区别并不大。

三个版本的 Sass 编译速度对比

上图是 Dart Sass on Dart-VM、Dart Sass on NPM、Node Sass 分别去编译 BootStrap 4 的耗时(来源于 Stack Overflow),可以看出 Dart Sass on NPM(即 Dart Sass JS)比 Node Sass 还要慢很多(大概3倍的耗时),但实际上即使是 Bootstrap 这个体量,也只是2秒的耗时,考虑到官方和社区都逐步迁移到 Dart Sass 了,因此新项目也建议使用 Dart Sass。

]]>
https://kayosite.com/analysis-of-sass-breaking-change-slash-as-division.html/feed 0 3753
SassDoc 详细介绍与最佳实践 https://kayosite.com/sassdoc-introduction-and-best-practices.html https://kayosite.com/sassdoc-introduction-and-best-practices.html#respond Mon, 22 Aug 2016 08:20:00 +0000 https://kayosite.com/?p=3543 SassDoc 是一款专门为 Sass 代码生成注释的工具,通过 SassDoc,开发者可以通过类似 JSDoc 的方式在 Sass 代码上添加注释,然后直接用命令生成文档。最近在处理团队框架 QMUI Web 时,遇到了需要为大量 Sass 方法写文档的问题,因此研究了这个工具,本文将会详细说明 SassDoc 的使用方法以及其中的最佳实践。

基本使用

在 Sass 中,可以使用多行注释 /* xxxx */ 和单行注释 // xxxx 两种注释方法。如文章开头所述,SassDoc 是使用类似 JSDoc 的方式,即在代码中通过注释编写文档内容的方式生成文档,因此 SassDoc 有特定的注释语法:

/// 跨浏览器的渐变背景,垂直渐变,自上而下
///
/// @group 外观
/// @name gradient_vertical
/// @param {Color} $start-color [#555] - 渐变的开始颜色
/// @param {Color} $end-color [#333] - 渐变的结束颜色
/// @param {Number} $start-percent [0%] - 渐变的开始位置,需要以百分号为单位
/// @param {Number} $end-percent [100%] - 渐变的结束位置,需要以百分号为单位
@mixin gradient_vertical($start-color: #555, $end-color: #333, $start-percent: 0%, $end-percent: 100%){
  background-image: -webkit-gradient(linear, left top, left bottom, color-stop($start-percent, $start-color), color-stop($end-percent, $end-color)); // Safari 4-5, Chrome 1-9
  background-image: -webkit-linear-gradient(top, $start-color $start-percent, $end-color $end-percent);  // Safari 5.1-6, Chrome 10+
  background-image: -moz-linear-gradient(top, $start-color $start-percent, $end-color $end-percent); // Firefox 3.6+
  background-image: -o-linear-gradient(top, $start-color $start-percent, $end-color $end-percent);  // Opera 12
  background-image: linear-gradient(to bottom, $start-color $start-percent, $end-color $end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+
  background-repeat: repeat-x;
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{ie-hex-str($start-color)}', endColorstr='#{ie-hex-str($end-color)}', GradientType=0); // IE9 and down
}

总结如下:

  • 使用 /// 作为 SassDoc 的注释标识(旧版的 SassDoc 中,使用的是 Sass 的注释方式,但这样这些注释也会被输出到 CSS 代码中,因此最新版的 SassDoc 选择重新定义一个 /// 作为专属的注释方式)
  • /// 中的第一行没有任何标记的文字会被当作 Sass 方法的描述
  • 带有 @name@param 这类标记的会当作对应的注释属性,完整的标记列表可以参考 http://sassdoc.com/annotations/

按照以上的方法,在 Sass 代码上写好了需要的注释,接下来就应该输出文档了。输出文档首先要安装 SassDoc 工具:

npm install sassdoc -g

然后对需要生成文档的 Sass 文件执行如下命令:

sassdoc sassFileName

例如:对 _compatible.scss 执行上面的操作,会直接生成如下的文档页面:

Sassdoc 示例
SassDoc 默认效果示例

如上图各个方法已经根据注释的内容输出对应的文档,并且文档的样式也很完善。至此,就是 SassDoc 的基本使用。

进阶使用

使用非默认主题以及其他选项

如果对默认的样式不满意,也可以使用官网提供的其他主题,在介绍如何使用其他主题时,先要介绍一下 SassDoc 的选项:

  • dest SassDoc 的输出目录,默认为 ./sassdoc
  • exclude 排除某些 Sass 文件,可以使用 * 通配符,类型为数组
  • package 类型为 String 或 Object,该选项可以告知 SassDoc 项目的标题,版本号等信息,默认值为 ./package.json
  • theme 文档的主题,默认为 default
  • autofill 规定那些属性需要尽量自动补全,默认为 ["requires", "throws", "content"]
  • groups 该方法的分组,文档中会根据把同一个分组的方法归类到一起展示,默认为 { undefined: "general" }
  • no-update-notifier 在使用 SassDoc 时(例如执行输出文档的命令),如果当前的 SassDoc 不是最新版本,会有输出提示,这个选项可以控制取消这个提示,默认为 false
  • verbose SassDoc 默认不会输出各个文档的生成进度,如果需要可以把这个选项设置为 true
  • strict 严格模式,默认为 false,开启后则使用一些废弃语法会报错(例如上面提到的旧版中可以使用的多行注释)

可以看出,如果希望使用其他主题,只需要下载对应的主题,并且在 theme 这个选项中进行配置即可,官方的其他主题列表

文件级注解

SassDoc 提供了一个文件级注解的功能,文件级注解与上面的普通注解相似,但是并不是书写在每个方法之上,而是写在文件的开头,它作用是当方法的注解缺少某些属性时,会自动把文件级注解当作缺省值使用。

例如在 _calculate.scss 中,方法的注解中都没有写 group 这个属性,但在文件级注解中有 group 属性,后续生成的文档都会以文件级注解中的 group 值当作自身的值。

代码:

////
/// 辅助数值计算的工具方法
/// @author Kayo 
/// @group 数值计算 
/// @date 2015-08-23
////

/// 获取 CSS 长度值属性(例如:margin,padding,border-width 等)在某个方向的值
///
/// @name getLengthDirectionValue
/// @param {String} $property - 记录着长度值的 SASS 变量 
/// @param {String} $direction - 需要获取的方向,可选值为 top,right,bottom,left,horizontal,vertical,其中 horizontal 和 vertical 分别需要长度值的左右或上下方向值相等,否则会报 Warning。
/// @example
///   // UI 界面的一致性往往要求相似外观的组件保持距离、颜色等元素统一,例如:
///   // 搜索框和普通输入框分开两种结构处理,但希望搜索框的搜索 icon 距离左边的空白与
///   // 普通输入框光标距离左边的空白保持一致,就需要获取普通输入框的 padding-left
///   $textField_padding: 4px 5px;
///   .dm_textField {
///     padding: $textField_padding;
///   }
///   .dm_searchInput {
///     position: relative;
///     ...
///   }
///   .dm_searchInput_icon {
///     position: absolute;
///     left: getLengthDirectionValue($textField_padding, left);
///     ...
///   }
@function getLengthDirectionValue($property, $direction) {
  ...
}

效果:

数值计算方法的效果
文件级注释示例

最佳实践

完全自定义外观

如果你不喜欢 SassDoc 提供的主题,或者本身的文档有一整套样式(例如上面提到的框架有自己的完整官网,因此 Sass 方法的文档也需要配合官网的风格),那么你就需要完全自定义样式。对开发者来说,常用的思路应该是把 Sass 代码中的注释输出为特定格式,例如 JSON,然后页面中通过读取这些数据输出 HTML。

SassDoc 中也提供了一些相关的接口,第一步是把指定的 Sass 文件读取出里面的注解,并输出数组,在此之前,你需要建立一个脚手架,方便你调用这个任务,持续地更新你的文档,例如使用 Gulp,首先在本地目录安装 SassDoc:

npm install sassdoc --save-dev

然后建立一个 Gulp 的 Task:

gulp.task('readToolMethod', false, function(){
  var sassdoc = require('sassdoc');

  sassdoc.parse([
    './qmui/helper/mixin/'
  ], {verbose: true})
  .then(function (_data) {
    // 文档的数据
    console.log(_data);
  });
});

可以看到,会输出数组格式的数据,并把每个方法作为一个 Object,Object 中包含了各个注解属性及其属性值:

SassDoc 解析出的数据格式
SassDoc 解析出的数据格式

接下来,你就可以根据这个数据拼接 HTML 了。

数据分组

SassDoc 中输出的数组数据并没有按不同 Group 把方法归类到不同的数组中,但在拼接 HTML 时,我们一般需要把方法按 group 归类到不同的数组中,方便遍历。这里给出一个方法,把刚刚的数组按 group 拆分成二维数组:

gulp.task('readToolMethod', false, function(){
    var fs = require('fs'),
      sassdoc = require('sassdoc'),
      _ = require('lodash');

  sassdoc.parse([
    './qmui/helper/mixin/'
  ], {verbose: true})
  .then(function (_data) {
    if (_data.length > 0) {
      // 按 group 把数组重新整理成二维数组
      var _result = [],
          _currentGroup = null,
          _currentGroupArray = null;
      for (var _i = 0; _i < _data.length; _i++) {
        var _item = _data[_i];
        // 由于 IE8- 下 default 为属性的保留关键字,会引起错误,因此这里要把参数中这个 default 的 key 从数据里改名
        if (_item.parameter) {
          for (var _j = 0; _j < _item.parameter.length; _j++) {
            var _paraItem = _item.parameter[_j];
            if (_paraItem.hasOwnProperty('default')) {
              _paraItem['defaultValue'] = _paraItem['default'];
              delete _paraItem['default'];
            }
          }
        }

        if (!_.isEqual(_item.group, _currentGroup)) {
          _currentGroup = _item.group;
          _currentGroupArray = []; 
          _result.push(_currentGroupArray); 
        } else {
          _currentGroupArray = _result[_result.length - 1];
        }
        _currentGroupArray.push(_item);
      }
      _result.reverse();

      // 准备把数组写入到指定文件中
      var _outputPath = './qmui_tools.json';

      // 写入文件
      fs.writeFileSync(_outputPath, 'var comments = ' + JSON.stringify(_result), 'utf8');
    }
  });
});

上面演示了如何把数组按 group 拆分为二维数组,并以 JSON 格式写入到文件中,方便拼接 HTML。需要注意的是,@param 这个注解中有一个 default 属性,代表参数的默认值,因此生成 JSON 后会产生一个 default 属性,在 IE8- 下,default 为属性的保留关键字,直接使用会引起错误,因此这里要把参数中这个 default 的 key 从数据里重命名,避免发生这种错误。

重新拼接方法体

在书写文档时,一般需要列出方法体(即完整的方法声明),例如:

onePixelBorder 方法
方法主题展示示例

SassDoc 输出的数据中本身不包含方法体,但是提供了组成方法体需要的数据,下面的方法可以利用一个 SassDoc 的 item 拼接处完整的方法体:

var makeCompleteMethodWithItem = function(item) {
  var result = '',
      itemType = null;

  if (item.context.type === 'placeholder') {
    itemType = '%';
  } else {
    itemType = item.context.type + ' ';
    result = '@';
  }

  result = result + itemType + item.context.name;
  if (item.parameter) {
    result += '(';

    var paraList = item.parameter;
    for (var paraIndex = 0; paraIndex < paraList.length; paraIndex++) {
      var paraItem = paraList[paraIndex];
      if (paraIndex !== 0) {
        result += ', $';
      } else {
        result += '$';
      }
      result += paraItem.name;
      if (paraItem.defaultValue) {
        result = result + ': ' + paraItem.defaultValue;
      }
    }
    result += ')';
  }
  result += ' { ... }';

  return result;
};

SassSDocMeister

最后推荐一款官方的工具—— SassSDocMeister,这个工具可以在线预览 SassDoc 注解的效果,对于刚接触 SassDoc 的用户来说会比较方便。

完整的 Demo 请参考 QMUI WebQMUI Web Demo,如果你觉得这篇文章对你有帮助,欢迎 Star。

]]>
https://kayosite.com/sassdoc-introduction-and-best-practices.html/feed 0 3543
为 IE 单独写 CSS 的几种方法 https://kayosite.com/the-methods-make-css-only-for-ie.html https://kayosite.com/the-methods-make-css-only-for-ie.html#comments Fri, 17 May 2013 08:42:34 +0000 http://kayosite.com/?p=3166 因为万恶的 IE 存在各种的不标准,因此,在进行页面开发时不免要为 IE 单独写一些 CSS 。熟悉的方法有 IE hacks 和条件注释 CSS(Conditional Stylesheets),下面,不妨讨论一下这两种方法的优缺点。

IE hacks

举个例子,一个元素在其他浏览中的左边距是 30px ,而在 IE6 中则设置为 20px ,可以如下编写:

.demo {margin-left: 30px; _margin-left: 20px; }

对我个人而言,喜欢条件注释 CSS 是胜于 IE hacks ,光是 IE hacks 里面带有“hacks”这个单词已经让人很不舒服,总觉得这是偏方,而且是很偏的解决方案。但是,IE hacks 也有它的优点——

  • CSS hacks 内嵌在普通的 CSS 里面,不会产生更多 HTTP 请求。
  • CSS hacks 内嵌在普通的 CSS 里面,编写时比较方便。

当然,它的缺点也很明显——

  • 它是不标准的产物。
  • 内嵌在其他 CSS 中,不便维护。尤其是当 hacks 的数量比较多的时候维护简直是个恶梦。
  • 内嵌在其他 CSS 中,即使在非 IE 浏览器中也会被加载,浪费资源。

条件注释 CSS

同样是上面的例子,如果使用条件注释 CSS ,可以如下编写:

HTML

<!--[if IE 6 ]>
    <link rel="stylesheet" type="text/css" media="all" href="./ie6.css" />
<![endif]-->

ie6.css

.demo {margin-left: 20px; }

这里说明一下:条件注释是一种 IE 专有的、对常规(X)HTML 注释的 Miscrosoft 扩展。从 W3C 标准来说,它也是不标准的产物,但它是微软官方推出的针对 IE 进行开发的方式,并且条件注释对于其他所有浏览器作为常规注释出现,因此对其他浏览器无害。

条件注释 CSS 的好处是在独立的 CSS 文件中编写,能准确控制在特定的 IE 中加载,不会造成资源浪费,并且便于维护。缺点就是会产生多余的 HTTP 请求,尤其是当你需要兼容的 IE 版本很多的时候,你就需要产生多个 HTTP 请求,这对于本来通道数目就少的低版本 IE 来说无疑会影响页面加载速度。

显然,以上两种方法都不是很好的方法,因此,接下来介绍一种相对来说更好的解决方案。

条件注释 html 标签

这种方案也是利用条件注释,但并不是对 CSS 使用条件注释,而是对 html 标签使用条件注释,引入不同的 class ,从而区分不同的 IE 以及其他浏览器。例如:

<!DOCTYPE html>
<!--[if IE 6 ]> <html class="ie6 lte_ie6 lte_ie7 lte_ie8" lang="zh-CN"> <![endif]-->
<!--[if lte IE 6 ]> <html class="lte_ie6 lte_ie7 lte_ie8" lang="zh-CN"> <![endif]-->
<!--[if lte IE 7 ]> <html class="lte_ie7 lte_ie8" lang="zh-CN"> <![endif]-->
<!--[if lte IE 8 ]> <html class="lte_ie8" lang="zh-CN"> <![endif]-->
<!--[if (gte IE 9)|!(IE)]><!--><html lang="zh-CN"><!--<![endif]-->

然后把针对特定 IE 的 CSS 加上相应的 class 并写在普通 CSS 文件里即可。例如上面的例子则可以在 CSS 文件里编写:

.ie6 .demo {margin-left: 20px; }

这种方法吸收了条件注释表达式的好处同时又不会产生多余的 HTTP 请求,只是由于这些针对特定 IE 的 CSS 与普通的 CSS 放在一起,即不是相应的 IE 也会被加载,因此如果 CSS 数目比较多的话就会像使用 hacks 那样,造成浪费,开发者需要根据具体情况选择方法。

]]>
https://kayosite.com/the-methods-make-css-only-for-ie.html/feed 33 3166
:hover 在 IE6 下的一个 Bug https://kayosite.com/ie6-hover-bug.html https://kayosite.com/ie6-hover-bug.html#comments Wed, 13 Mar 2013 11:01:13 +0000 http://kayosite.com/?p=3029 看到标题,相信会很容易联想到 IE6 不支持除 a 外的 :hover 伪类,不过这只能说是万恶的 IE6 对于 CSS 选择器的支持太差了,还不能说是 Bug 。而接下来 Kayo 要说明的,是个实实在在、不折不扣的 Bug 。

这个 Bug 是关于一个比较常用的效果 —— hover 后改变子元素效果。

例如,有如下的一个导航, hover 后的链接中的文字会改变颜色

<div id="nav">
	<ul>
		<li><a href="#" title="#"><span>链接一</span></a></li>
		<li><a href="#" title="#"><span>链接二</span></a></li>
		<li><a href="#" title="#"><span>链接三</span></a></li>
		<li><a href="#" title="#"><span>链接四</span></a></li>
		<li><a href="#" title="#"><span>链接五</span></a></li>
	</ul>
</div>
* {margin: 0; padding: 0; }
		
#nav {background: #2595e5; font-size: 16px; overflow: hidden; zoom: 1; }
#nav ul {list-style: none; }
#nav ul li {float: left; margin-left: 15px; padding: 8px; }
#nav ul li a {text-decoration: none; }
#nav ul li a span {color: #fff; }
#nav ul li a:hover span {color: #c6c6c6; }

情况很容易想象,当鼠标移到导航上的链接时,链接颜色变为白色,的确,在绝大数浏览器上都会如此,但在 IE6 上却没有反应。如下面的 Demo :

http://kayosite.com/demo/ie6-hover.html

那么,问题出现了,应该如何解决呢?

可以为 a:hover {} 添加一些属性,例如 margin ,padding 等,当然,为了不影响导航原来的布局,最好当然是添加 zoom: 1 ,为上面的 CSS 添加如下的一句:

#nav ul li a:hover {zoom: 1; }

如 Demo :http://kayosite.com/demo/ie6-hover-fix.html

于是又神奇地正常了,可能阅读到这里,会有读者认为,这肯定又是 hasLayout 在作怪,于是加入一个在 IE6 下不会触发 hasLayout 的属性 overflow: hidden ,结果可能你也猜到了,使用这个属性也能使到 :hover 恢复正常。

当然,IE6 是个奇葩,如果只是这样,我是不会觉得惊奇的,最神奇的是,加入一个不存在的属性 aaa:bbb 都能使到 :hover 恢复正常。因此,这个问题可以说是 IE6 下一个绝对的 Bug 了。

]]>
https://kayosite.com/ie6-hover-bug.html/feed 19 3029
一些惊艳的 CSS3 之二 https://kayosite.com/amazing-css3-part-two.html https://kayosite.com/amazing-css3-part-two.html#comments Mon, 25 Feb 2013 14:10:05 +0000 http://kayosite.com/?p=3015 接上一篇文章《一些惊艳的 CSS3 之一》

三. 多重背景

多重背景并没有使用新增的 CSS3 属性,而是在我们都很熟悉的 background-image 作出调整,支持同时使用多个图片,例如:传统来说,为元素设置背景图会像如下设置:

#demo {background: url(bg1.png) no-repeat; }

bb

但是在 CSS3 中,设计师可以同时为一个元素指定多个背景,例如:

#demo {background: url(bg1.png) no-repeat left top, url(bg2.png) no-repeat left bottom, url(bg3.png) no-repeat right top; }

mb

四. 嵌入字体类型

对于一个出色的网页,字体的选择是相对关键的,无奈设计师必须考虑用户的本地端是否有相应的字体,因此设计常常只能使用一些较为大众化的常见字体,而舍弃更加适合的字体。在 CSS3 中,这一情况将可以改变。CSS3 中引入了 font-face(嵌入字体类型),实验 font-face 可以把需要的字体上传到自己的服务器,再在服务器的网页中使用该字体并显示出来,无论浏览网页的用户的本地端是否有该字体。

这无疑是个很棒的功能,例如下面的效果:

font-face

部分文字使用了用 font-face 引入的字体,代码如下:

@font-face {
    font-family: 'vanessalovesyoumedium';
    src: url('vanessalovesyou-webfont.eot');
    src: url('vanessalovesyou-webfont.eot?#iefix') format('embedded-opentype'),
         url('vanessalovesyou-webfont.ttf') format('truetype'),
    font-weight: normal;
    font-style: normal;
}
#test-font {
	font-size: 24px;
}
#test-font span{
	font-family: vanessalovesyoumedium;
}

使用 @font-face 定义字体所需要的文件,为了兼容各个浏览器,需要使用多种不同的字体格式,建议至少要有 .eot 和 .ttf 两种格式,.eot 用于 IE5+ ,.ttf 用于 Chrome 等现代浏览器,另外 .otf 也是不错的选择,也可以用于现代浏览器。

浏览器支持如下:

Chrome 2.0.156+、Firefox 3.05+、Safari 3.2.1+、Opera 11.50+、IE5+

需要注意以下几点:

  • IE8及更早浏览器只支持微软自有的 .eot 格式
  • IE9.0-10.0部分支持 ttf 和 otf 字体格式
  • 现代浏览器大多支持 .ttf 和 .otf 两种格式
  • 现代浏览器需要从外部引用 @face-font 才能有效,IE 则可以直接在页面中使用 @face-font

]]>
https://kayosite.com/amazing-css3-part-two.html/feed 13 3015
一些惊艳的 CSS3 之一 https://kayosite.com/amazing-css3-part-one.html https://kayosite.com/amazing-css3-part-one.html#comments Mon, 25 Feb 2013 14:09:57 +0000 http://kayosite.com/?p=2968 最近对一些 CSS3 的新特性作出了不少的介绍说明,这些内容大多都是 CSS3 中相对比较普及的内容,其实 CSS3 还有很多很酷的特性,只是这些特性在浏览器支持和网站的具体使用上比较逊色,但是仍具有不少的魅力,今天这篇文章要介绍的就是几个比较酷而相对介绍较少的 CSS3 特性。

一. 边框新特性

在 CSS3 中,border 增加了两个新的特性,一是边框图片,而是在边框颜色中使用渐变色。

边框图片利用 border-image 属性实现,可以为一个元素指定一个图片作为边框,代替传统的线条边框,它有五个子属性:

border-image-source

设置边框图片的图片地址,只有设置了这个属性,才算是使用了边框图片,其值为 url() 的形式。

border-image-width

该属性指定边框厚度,其值可以为带单位的长度值,也可以是不带单位的浮点值或百分比,还可以是“auto”,这时其值为 border-image-slice 的值,“auto”值很常用,可以方便地做出类似相册边框的精致边框。

border-image-slice

该属性指定从上,右,下,左方位来分隔图像,将图像分成4个角,4条边和中间区域共9份,中间区域始终是透明的(即没图像填充),除非加上关键字 fill,其值可以为数值或百分比。例如:设置 border-image-slice: 20 25 30 35; border-image-slice: auto,则图像会产生像下图那样的四个角:

原图划分示意图:

border-image-slice

实际效果图

border-image-slice-result

border-image-outset

该值设置边框图片的扩展,相当于在边框内容加入“padding”。

border-image-repeat

设置用何种方式填充边框,其值可以为 stretch、repeat、round、space,stretch 是拉伸方式,repeat、round 和 space 方式都是平铺方式,但三个之间略有不同,repeat 是直接平铺图片,图片若超出边框时截断,round 会动态调整图片的大小,直到图片正好可以铺满整个边框,space 则会在图片之间增加空白,直至图片正好可以铺满整个边框。

值得注意的是,直至 Chrome 23, Firefox 17, Safari 5.1.7, Opera 12.5 ,IE 10 ,仅有 Firefox 支持 round ,没有任何浏览器支持 space 。

接下来是边框梯度颜色,相对边框图片,边框梯度颜色的浏览器支持度就更低了,暂时只有 Firefox 能通过私有属性支持。但作为一个很酷的效果,也可以先留意一下:

.gradientcolor{
	border: 6px solid #fff;
	-moz-border-bottom-colors: #ff9900 #99cc33 #ccc;
	-moz-border-top-colors:    #ff9900 #99cc33 #ccc;
	-moz-border-left-colors:   #ff9900 #99cc33 #ccc;
	-moz-border-right-colors:  #ff9900 #99cc33 #ccc;
}

效果如下:

border-gradient

二. 多栏布局

多栏布局也是一个很惊喜的属性,它可以很方便地让设计师生成多栏,而无需复杂的 div 辅助,例如下面的效果:

column

在 CSS 2.0 中,要实现以上的效果的常见方法是用 div 包含每一个栏的内容,然后对几个 div 使用浮动。这样不但增加了几个无用的 div ,还可能损害了段落原本的语义,而在 CSS3 中,则可以使用以下代码实现这样的效果:

#column-demo {
	width: 960px;
	margin: 0 auto;
	-webkit-column-count: 4;
	-moz-column-count: 4;
	column-count: 4;
	-webkit-column-gap: 25px;
	-moz-column-gap: 25px;
	column-gap: 25px;
}
#column-demo p, #column-demo h2 {
	margin-bottom: 20px;
	color: #565656;
}
#column-demo h2 {
	font-size: 26px;
	-webkit-column-span: all;
	-moz-column-span: all;
	column-span: all;
}

这里说明一下,column-count 设置的是栏目的数量,即把内容分为几个栏目,column-gap 设置的是栏目的之间的距离,column-span 可以把一个元素设置为横跨所有栏目,还有一个常用的属性 column-width ,用于设置每个栏目的宽带,若像上例这样没有设置 column-width ,则会根据 column-count 自适应分配宽度。更多的相关属性可以浏览 W3C

column 的浏览器支持情况如下:

Chrome 13+ (准确最早支持版本不详,但至少已在 13 版时通过私有属性支持)、Firefox 3.5+、Safari 3+、Opera 11+、IE 10)

小提示:以上只代表浏览器已支持 column 的基本使用,即最起码支持 column-count 和 column-width ,而并不代表浏览器支持 column 的所有相关属性,并且最新版本的 Chrome(23.0.1271.97)和 Firefox(18.0)仍需要通过各自的私有属性才能支持 column 。

三、四两部分内容请浏览《一些惊艳的 CSS3 之二》

]]>
https://kayosite.com/amazing-css3-part-one.html/feed 9 2968
CSS3 自定义动画(animation) https://kayosite.com/css3-animation.html https://kayosite.com/css3-animation.html#comments Wed, 09 Jan 2013 13:57:30 +0000 http://kayosite.com/?p=2919 除了在之前的文章中介绍过的 CSS3 的变形 (transformation) 和转换 (transition) 外,CSS3 还有一种自由度更大的自定义动画,开发者甚至可以使用变形(transformation)和转换(transition)制作自定义动画,利用纯 CSS 制作出像 Flash 一样的效果。在实际使用中不难发现,变形和转换更适合做元素的交互,而自定义动画除了做交互外还能使到网页具有活力,有了自定义动画,利用 CSS 代替 Flash 才会更加现实。

首先看看 animation 的效果 —— Demo

一. animation 基础

animation 的参数与 transition 比较相似,如果之前了解过 transition 的童鞋应该会对 animation 的参数感觉很熟悉。具体的参数如下:

animation-name

动画名称,默认为 none

animation-duration

动画的持续时间,默认为 0

animation-timing-function

动画的过渡类型,参数可选值类似于 transition-timing-function ,默认为 ease ,具体如下:

  • linear:线性过渡。相当于贝塞尔曲线(0.0, 0.0, 1.0, 1.0)
  • ease:平滑过渡。相当于贝塞尔曲线(0.25, 0.1, 0.25, 1.0)
  • ease-in:由慢到快。相当于贝塞尔曲线(0.42, 0, 1.0, 1.0)
  • ease-out:由快到慢。相当于贝塞尔曲线(0, 0, 0.58, 1.0)
  • ease-in-out:由慢到快再到慢。相当于贝塞尔曲线(0.42, 0, 0.58, 1.0)
  • cubic-bezier(number, number, number, number):特定的贝塞尔曲线类型,number 在 [0, 1] 区间内取值

animation-delay

动画延迟的时间

animation-iteration-count

动画的循环次数,其值可以是一个正整数,表示循环次数,也可以设置为 infinite ,即无限循环,默认为 1

animation-direction

动画在循环中是否反向运动,normal 为正向方向,alternate 为向常与反向交替运动,具体为第偶数次正向运动,第奇数次向反方向运动,默认为 normal

animation-play-state

表示动画的状态,默认值为 running ,表示正在运动,paused 为暂停。但 w3c 正在考虑是否将该属性移除,并通过重设样式或其他方式表示动画的状态,因此不建议使用该属性。

以上这些参数都可以同时赋予多个值,只要注意各参数顺序对应即可,例如要为 #demo 指定两个动画,可以这样编写(大多数浏览器仍需通过私有属性才能支持 animation ,为了方便阅读,这里省略浏览器私有属性,按 W3C 标准写法编写。)

#demo {
	/* 指定动画名称 */
	animation-name: animation1, animation2;
	/* 指定动画时长 */
	animation-duration: 2s 1s;
}

这样 #demo 就会同时获得两个动画,但是,动画的具体过程还没有指定,实际上动画的具体内容并不在 animation 内指定,而是利用另一个属性 @keyframes 指定,@keyframes 指定了一个动画的名称和实际内容,而 animation 则负责为元素指定引用的动画,并对动画的时间、过渡类型等作出设置。这样把动画的引用和动画的实际内容分开设置,可以提高动画的独立性和利用率。

@keyframes 支持两种设置方式,分别用于简单动画和复杂的动画

例如,为 #demo 设置一个简单的线性动画,使到其 opacity 值由 0 线性过渡到 1,可以直接使用 from 和 to 指定初始和结束状态,

#demo {
	animation-name: animation1;
	animation-duration: 2s;
	animation-timing-function: linear; 
}

@keyframes animation1{
	from{opacity: 0; }
	to{opacity: 1; }
}

若对于复杂的动画,则需要使用 percentage ,percentage 即百分比,animation 支持使用“%”指定到某一个百分比时动画所执行到的效果,例如指定元素向右平移再向下平移,可以这样编写:

#demo {
	animation-name: animation1;
	animation-duration: 2s;
	animation-timing-function: linear; 
}

@keyframes animation1{
	0% {transform: translate(0); }
	20% {transform: translate(120px); }
	40% {transform: translate(240px); }
	60% {transform: translate(240px, 40px); }
	80% {transform: translate(240px, 80px); }
	100% {transform: translate(240px, 120px); }
}

也可以配合 from 和 to 使用:

#demo {
	animation-name: animation1;
	animation-duration: 2s;
	animation-timing-function: linear; 
}

@keyframes animation1{
	from {transform: translate(0); }
	20% {transform: translate(120px); }
	40% {transform: translate(240px); }
	60% {transform: translate(240px, 40px); }
	80% {transform: translate(240px, 80px); }
	to {transform: translate(240px, 120px); }
}

当然,开发者也可以合并 animation 的各个单独属性,直接用 animation 简写:

#demo {
	animation: animation1 2s linear;
}

@keyframes animation1{
	0% {transform: translate(0); }
	20% {transform: translate(120px); }
	40% {transform: translate(240px); }
	60% {transform: translate(240px, 40px); }
	80% {transform: translate(240px, 80px); }
	100% {transform: translate(240px, 120px); }
}

效果请浏览 Demo(请使用 Chrome、Firefox、Safari 或 Opera 浏览,下同)。

二. 动画的内容

animation 配合 transform 无疑能做出一些不错的动画,但 animation 的能力不仅限于此,W3C 提供给 animation 可用于做动画过程的 CSS 属性有很多种,包括了元素的宽度(width)、高度(height)、边距(margin)、背景(background)等重要属性,具体请浏览 W3C 官方说明。熟悉 jQuery 的童鞋会发现,animation 与 jQuery 的 animate() 方法很相似,但 animate() 只支持数值类型动画,而不支持如颜色值等字符串值,在这点上 animation 更有优势,并且是纯 CSS 实现,无须包含一个 jQuery 库。当然,与 jQuery 已经做好完善的浏览器兼容相比,CSS3 的 animation 则显得有点逊色,因此暂时还是建议把 animation 渐进增强地用在网页效果与交互加强中,关于这一点文章末尾会再作论述。

另外,transition 中的过渡属性可选值(transition-property)也是使用上面的值。

三. animation 与 transform 和 transition 的区别

很多的资料会把 transform 和 transition 同时直接归类为动画,的确,从很多实际使用的例子中看,transform 和 transition 都表现出动画的特征,但实际上,它们仍有很大的区别:

transform 和 transition 需要经过用户触发才会表现出动态的效果,这些触发条件可以是:link、:visited、:hover、:active 和 :focus 五个 CSS 伪类,也可以是 click、focus 等 JavaScirpt 事件,如果没有设置触发条件而直接给元素设置 transform 或 transition ,用户只能看到元素的终态而没有动画过程。animation 则无须触发条件,开发者只需为元素绑定动画即可。

另外,在旧版本的 animation 中,animation 、transform 以及 transition 都有一个重要的性质——过程执行完毕后会回撤,例如以 :hover 触发 transform ,在鼠标离开元素后动画自动反向播放,使到元素回到 transform 之前的状态,animation 也会在动画结束后回滚,但不会反向播放动画,而是直接跳到动画播放之前的动态。

但是,经过修订,animation 增加了一个很重要的属性 animation-fill-mode ,这个属性控制设置动画之外的状态,即元素在动画开始前后的状态是否根据动画设置中“0%”、“100%”的状态设置,animation-fill-mode 的值可以为 none、forwards、backwards 或 both ,默认为 none ,即动画过程中“0%”、“100%”的状态不会设置为元素开始和结束的状态,backwards 和 forwards 则分别设置开始和结束的状态,both 则同时设置两个的状态,例如上面平移元素的例子,若加入 forwards 属性,则在动画结束后元素会保留在 100% 时动画设置的位置而不回撤。读者可以根据下面的 Demo 对比两者的不同之处。

设置了 forwards 的 Demo

有了这个属性,animation 动画也就更加完整了,虽然没有了这个属性,开发者仍可以设置出自己需要的效果,但是 animation 是需要配合其他 CSS 属性设置才会有最终的效果,若没有了这个属性设置动画将会复杂很多。

四. 浏览器兼容

animation 的兼容性如下:

Chrome 13+、Firefox 5+、Safari 5.1+、Opera 12+、IE10+

其中最新版的 Chrome、Safari、Opera 以及 IE(Chrome 22.0.1229.94 , Firefox 17.0.1 , Safari 5.1.7 , Opera 12.12 , IE10)需要通过私有属性才能支持 animation ,Firefox 则支持 W3C 的标准写法。

虽然 animation 的浏览器支持情况仍稍有欠缺,但 animation 的效果真的十分出色,开发者不妨利用渐进增强的设计理念,把 animation 用在增强页面元素的效果或交互上,这样对于使用现代浏览器的用户来说无疑会提升他们的用户体验。

当然,如果 animation 中还使用了 transform 或 transition ,那么兼容性则需要考虑到 transform 或 transition 的浏览器兼容性。考虑到综合的情况,Kayo 建议使用如下的方式调用 animation (以简单动画为例子):

#demo {
	-webkit-animation: animation1 2s linear;
	-moz-animation: animation1 2s linear;
	-o-animation: animation1 2s linear;
	animation: animation1 2s linear;
}

@-webkit-keyframes animation1{
	from{opacity: 0; }
	to{opacity: 1; }
}

@-moz-keyframes animation1{
	from{opacity: 0; }
	to{opacity: 1; }
}

@-o-keyframes animation1{
	from{opacity: 0; }
	to{opacity: 1; }
}

@keyframes animation1{
	from{opacity: 0; }
	to{opacity: 1; }
}

]]>
https://kayosite.com/css3-animation.html/feed 11 2919
更多的 CSS3 变形 (transformation) https://kayosite.com/more-about-css3-transformation.html https://kayosite.com/more-about-css3-transformation.html#comments Sun, 06 Jan 2013 11:06:57 +0000 http://kayosite.com/?p=2880 在 Kayo 之前所写的一篇文章《CSS3的变形与过渡样式》中,曾经对 CSS3 的变形 (transformation) 和转换 (transition) 作出详细介绍,但关于变形的部分内容仍可以扩展说明一下,因此写了本文补充一下变形的相关内容。

在前文中,已经说明了 transform 属性的两个用法 rotate 和 scale ,分别用于对象的旋转和缩放,具体的内容可以阅读前文。而现在要补充说明的,是 transform 的另外 3 个方法,translate、skew 以及 matrix 。

这些方法都有 2D 和 3D 的方式,在这里 Kayo 首先说明 2D 情况下的效果,并以此为基础再拓展说明 3D 下的效果。

一. translate

translate 为指定对象的平移,具有两个参数,第一个为 x 轴方向平移,第二个为 y 轴方向平移。如果第二个参数未提供,则默认值为 0 。

例如,需要设置一个元素在鼠标悬停时进行 x 轴方向 30px 和 y 轴方向 20px 的平移,可以这样编写:

#translate-demo:hover {
	-webkit-transform: translate(30px, 20px);
	-moz-transform: translate(30px, 20px);
	-o-transform: translate(30px, 20px);
	-ms-transform: translate(30px, 20px);
	transform: translate(30px, 20px);
}

translate

也可以浏览 Demo(请使用 Chrome、Firefox、Safari 或 Opera 浏览,下同)。

这里必须说明一点,最新版本的主流现代浏览器(Kayo 测试的是 Chrome 22.0.1229.94 , Firefox 17.0.1 , Safari 5.1.7 , Opera 12.12)除 webkit 内核的 Chorme 和 Safari 外都不需要通过私有属性才能支持 transform 了,但由于早期的现代浏览器中 transform 属性都需要通过各自的私有属性支持,因此为了尽量兼容早期版本的浏览器,在实际项目中使用 transform 时最好使用各自的私有属性,同时为了向后兼容,需要加上没有私有属性的调用。

二. skew

skew 指定元素斜切扭曲,即元素围绕 x 轴和 y 轴进行倾斜,具有两个参数,第一个对应 x 轴方向的倾斜角度,第二个对应 y 轴方向倾斜角度。如果第二个参数未提供,则默认值为 0 。skew 与 scale 有点相似,但 scale 只旋转元素,不会对元素形状作出改变,而 skew 则会使到元素的形状发生改变。

例如,需要设置一个元素在鼠标悬停时进行 x 轴方向 30 度和 y 轴方向 30 度的斜切扭曲,可以这样编写:

#skew-demo:hover {
	-webkit-transform: skew(30deg, 30deg);
	-moz-transform: skew(30deg, 30deg);
	-o-transform: skew(30deg, 30deg);
	-ms-transform: skew(30deg, 30deg);
	transform: skew(30deg, 30deg);
}

skew

也可以浏览 Demo

值得注意的是,由于 translate、skew 以及上文提到的 scale 都是以 x、y 轴相关的值作为参数,因此为了方便起见,W3C 还提供了 translateX 和 translateY 、skewX 和 skewY 以及 scaleX 和 scaleY 方法,分别用于独立设置 x 轴和 y 轴方向上的效果。

三. matrix

matrix 即矩阵,这里具体使用的是一个 3*3 矩阵。

用矩阵表示属性值?

是的,除了 transform 外,CSS3 中另外还有一些属性以 matrix 作为属性值,实际上,matrix 是 transform 中最基本而又最强大的值,上面的 translate 和 skew 以及之前介绍过的 rotate 和 scale 在底层都是通过 matrix 实现的,因此实际上所有的 transform 值都可以通过一个 3*3 矩阵表示。

我们知道,transform 是在 x、y 坐标系上的 2D 变换,因此实际上变换就是元素上每一个点通过一个变换等式进行变化,再产生新的坐标值的过程。因此我们设置旧的 x、y 坐标值分别为 XprevCoordSys 和 YprevCoordSys ,新的 x、y 坐标值分别为 XnewCoordSys 和 YnewCoordSys ,由于变换在 2D 中进行,因此 z 坐标值设为 1 即可。这时再另设 matrix 为如下的一个矩阵,

Matrix

则旧的坐标值、新的坐标值与 matrix 中存在如下关系:

MatrixMultiply

即新旧值之间可以通过矩阵连成等式,因此开发者只需要设定好 matrix 的值,就可以写出自定义的变换了。接下来需要注意,虽然 matrix 是一个 3*3 矩阵,在实际使用时只需填写6个参数(另外3个与 x、y 轴无关),并且调用时需要用如下的顺序 [a b c d e f]

例如编写如下语句:

#matrix-demo:hover {
	-webkit-transform: matrix(1, 1, 0, 1, 0, 0);
	-moz-transform: matrix(1, 1, 0, 1, 0, 0);
	-o-transform: matrix(1, 1, 0, 1, 0, 0);
	-ms-transform: matrix(1, 1, 0, 1, 0, 0);
	transform: matrix(1, 1, 0, 1, 0, 0);
}

这样在鼠标悬停时元素会在 y 轴方向上拉伸(即相当于 skewY(45deg) 的效果)。

也可以浏览 Demo

另外如果同时使用两个或以上的 transform 方法,可以把它们合并书写。

四. 3D transformation

上面讨论的是 2D 下的 CSS3 变形,实际上有部分 transform 方法支持 3D 变形,包括 scale()、translate()、scale() 和 matrix() ,W3C 增加了一些附加方法实现 3D 效果,包括增加了相应的 3D 方法 scale3d()、translate3d()、scale3d() 和 matrix3d() ,这些方法的参数也增加了一个 “z” ,定义 z 方向的效果。定义变形中心的 transform-origin() 方法也增加了 z 参数,用于设置 z 方向上的变形中心。另外还增加了 scaleZ()、translateZ() 和 scaleZ() ,用于单独设置 z 方向上的效果。

值得一提的是,W3C 还为 3D transform 定义了 perspective() 方法和 transform-style() 方法。

transform-style() 方法用于设置元素的子元素是否参与 3D 变形,它具有两个可选值,flat 和 preserve-3d ,分别设置子元素不参与 3D 转换和子元素将显示在 3D 环境中。

perspective() 的作用则复杂很多,在说明 perspective() 的作用之前,我们首先说明一下 transform 产生 3D 效果的方式:

  • transform 使用透视方式,即近大远小的方式在视觉上产生 3D 效果。
  • 所有元素都是假设被放置在 z = 0 的平面上,我们直视屏幕的方向(镜头方向)只能是平行 z 轴向屏幕内,也就是从屏幕正前方向里看
  • 可以通过 transform-origin 调整镜头与元素所在平面的角度

视觉 3D 是通过镜头距离和角度的调整达到更加真实的效果,因此结合 transform 实现 3D 的方式,除了使用 transform-origin 调整镜头中心外,我们还需要一个方法调整镜头与元素所在平面的距离,这个就是 perspective() 方法。

从定义上讲,perspective() 定义了镜头到元素的距离;从 3D 的效果来说,它对于 3D 效果的真实程度具有重要的影响。

例如,我们要使元素在 y 轴方向旋转 90 度,添加 perspective() 前后的效果如下:

#threed-demo:hover {
	-webkit-transform: rotateY(75deg);
	-moz-transform: rotateY(75deg);
	transform: rotateY(75deg);
}

增加 perspective() 之后

#threed-perspective-demo:hover {
	-webkit-transform: perspective(300px) rotateY(75deg);
	-moz-transform: perspective(300px) rotateY(75deg);
	transform: perspective(300px) rotateY(75deg);
}

具体的变化请浏览 Demo (请使用 Chrome、Firefox 或 Safari ,如果发现没有效果,请升级浏览器版本)。

可以看出,增加 perspective(300px) 后 3D 的效果真实很多了。但是,3D 效果的浏览器支持情况仍旧很差,下面会详细说明。

另外 perspective 方法需要写在其他方法之前才会有效果,关于这一点 W3C 以及浏览器文档都没有声明原因,使用时按照这个顺序书写即可。

五. 浏览器兼容

这里分开说明 2D 和 3D transform 的浏览器支持情况。

1. 2D

translate()、skew()、matrix() 三个方法与在前文中说明的 transform 的浏览器兼容性相当。

兼容浏览器:Firefox 3.5+、Chrome 2.0+、Safari 3.1+、Opera 10.50+、IE9 (早期版本通过浏览器各自的私有属性支持)

另外最新版本的 Chorme 和 Safari 仍需通过私有属性支持,最新版本的 Opera 则仍不支持 rotateY 等独立属性。

2. 3D

3D 的支持情况则糟糕很多,除了 webkit 内核外,其他主流浏览器对于 3D transform 的支持都比较晚,即使是最新版本的几个主流现代浏览器(Chrome 22.0.1229.94 , Firefox 17.0.1 , Safari 5.1.7 , Opera 12.12),支持情况也不良好,具体如下:

IE 和 Opera 并不支持任何 3D transform 。

最新版本的 Chrome、Firefox、Safari 都已经支持 3D transform 的变换方法,并且无需私有属性。

最新版本的 Chrome、Firefox、Safari 需要通过各自的私有属性支持 perspective() 。

最新版本的 Chrome、Safari 需要通过各自私有属性支持 3D transform-origin ,Firefox 则无需使用私有属性。

六. 总结

可以看出,2D transform 已经在现代浏览器甚至新版本的 IE 中获得良好的支持,开发者不妨使用 2D transform 为网页元素添加一些渐进增强的效果,使用时若需要兼顾较低版本的现代浏览器,需要使用以下方式调用(以文章开头的 translate 为例):

#translate-demo:hover {
	-webkit-transform: translate(30px, 20px);
	-moz-transform: translate(30px, 20px);
	-o-transform: translate(30px, 20px);
	-ms-transform: translate(30px, 20px);
	transform: translate(30px, 20px);
}

若只需考虑较新版本的浏览器(实验性网站),只按以下方式调用即可:

#translate-demo:hover {
	-webkit-transform: translate(30px, 20px);
	transform: translate(30px, 20px);
}

而 3D transform 的浏览器支持情况并不良好,只建议用于实验性网站,并通过以下方式调用(以 perspective 的例子说明):

#translate-demo:hover {
	-webkit-transform: perspective(300px) rotateY(75deg);
	-moz-transform: perspective(300px) rotateY(75deg);
	transform: perspective(300px) rotateY(75deg); /* 往后兼容 */
}

但是,3D transform 仍可以有很大的作用,由于, Chrome 和 Safari 都对 3D transform 有着良好的支持,因此,同样使用 webkit 内核的 Android 4.0 和 iphone/ipad 的默认浏览器对 3D transform 也有着良好的支持,只要设计的效果能被移动设备负担,用 3D transform 做一些比较酷的 Web Apps 会是一个不错的选择。

]]>
https://kayosite.com/more-about-css3-transformation.html/feed 9 2880
IE6 下 img 底部多出空白 https://kayosite.com/ie6-img-bottom-blank-bug.html https://kayosite.com/ie6-img-bottom-blank-bug.html#comments Fri, 21 Dec 2012 07:02:06 +0000 http://kayosite.com/?p=2868 是芥末日木有出现,Kayo 又可以继续写博客了。昨天在优化主题时意外的发现了 IE6 下 img 标签的一个 Bug ,用块级容器包裹 img 标签时,在 IE6 下 img 标签所在容器底部会出现 5px 多余的空白,例如网页中有如下的结构:

<ul>
<li><img src="img-bug.png" alt="img bug" /></li>
<li><img src="img-bug.png" alt="img bug" /></li>
<li><img src="img-bug.png" alt="img bug" /></li>
<li><img src="img-bug.png" alt="img bug" /></li>
<li><img src="img-bug.png" alt="img bug" /></li>
</ul>

相应的 CSS:

ul {list-style: none; }
li {display: block; width: 200px; height: 40px; }

在 Chrome 下,会显示如下的正确结果:

正确的渲染效果

但在杯具的 IE6 下,会显示如下的情况:

IE6下错误的渲染效果

接下来是如何解决问题了,解决的方案有很多种,这里 Kayo 列举几个比较好的解决方法:

方法一

方法一也是 Kayo 使用的方法了,就是为 img 标签的父元素添加 overflow: hidden 。

li {overflow: hidden; }

这个方法比较简单,只是父元素必须有指定的 height ,并且需要注意,某些情况下父元素可能需要显示超出自身大小的子元素(如显示绝对定位的超出父元素大小的子元素),这时使用 overflow: hidden 就不那么合适了。

方法二

为 img 标签设置 margin-bottom: -5px

img {margin-bottom: -5px; }

方法三

为 img 标签设置 vertical-align: bottom

img {vertical-align: bottom; }

]]>
https://kayosite.com/ie6-img-bottom-blank-bug.html/feed 25 2868
CSS3 之阴影效果 https://kayosite.com/css3-shadow-intro.html https://kayosite.com/css3-shadow-intro.html#comments Tue, 18 Dec 2012 15:22:53 +0000 http://kayosite.com/?p=2832 对于设计师来说,阴影可以说是一个很常用的效果,它可以直观地突显一个元素,用在网页设计上也非常适合。在 CSS3 阴影效果出现之前,开发者只能通过图片在网页表现阴影,尤其对于阴影文字,使用图片表示是很常见的方式,而在 CSS3 阴影出现后,设置元素的阴影将会变得轻松,下面详细介绍 CSS3 阴影。

一. CSS3 阴影基础

在 CSS3 中,阴影相关的具体属性有 text-shadow 和 box-shadow ,分别设置文字和容器阴影。

1. text-shadow

实际上,text-shadow 并不是在 CSS3 中才设计出的新属性,早在 CSS 2.0 时已经有了这个属性,之后在 CSS 2.1 中删去这个属性,最终在 CSS3 中重新纳入。

语法:text-shadow : offset-x || offset-y || opacity || color

该属性支持4个参数,分别是阴影颜色、阴影的水平延伸距离(阴影的 x 轴偏移)、阴影的垂直延伸距离(阴影的 y 轴偏移)、模糊效果的作用半径(阴影的长度)。也许这样介绍概念会有点难以理解,下面直接写一个小例子进行说明:

/* For text-shadow */
#example {text-shadow: 1px 1px 2px #d8d8d8; }

注:代码中省略与阴影设置无关的 CSS 代码(下同),完整 CSS 请参考文章末尾 Demo 的源码。

效果如下:

另外,text-shadow 也支持多重阴影,例如,要为一个文字同时设置三重阴影,可以这样编写代码:

/* For text-shadow 多重阴影 */
#example-muti {text-shadow: 1px 1px 2px #c10ccc, 1px 1px 2px #648cb4, 1px 1px 6px #cc150c; }

效果如下:

值得注意的是,在多重阴影中,阴影的顺序在不同版本的浏览器中表现不一定相同,由于在 CSS2.0 中,代码中最先定义的阴影会显示在最下面,而在 CSS3 中,最先定义的阴影则显示在最上面。在较新版本的现代浏览器中(Kayo 测试的是 Chrome 22.0.1229.94 , Firefox 17.0.1 , Safari 5.1.7 , Opera 12.11 )多重阴影的渲染顺序都已经按照 CSS3 的顺序了,但在早期版本的一些现代浏览器中仍会有差异,在介绍浏览器支持情况时会再说明一下这部分内容。

相对于图片来说,现在用一个属性就能解决问题实在简便很多。不过,也许你也已经猜到了,杯具的 IE 是不支持 CSS 阴影(所以 IE 版本都不支持 text-shadow IE8 及以下版本不支持 box-shadow ),因此针对 IE ,如果需要达到以上的同样效果,就需要使用 IE 私有滤镜 shadow 或 dropshadow 。这两个滤镜的具体使用也会有些不一样,下面详细介绍:

如果使用 shadow 滤镜,针对以上例子,开发者可以这样编写代码:

#example-ie {filter: progid:DXImageTransform.Microsoft.shadow(Color='#d8d8d8', Direction='135', Strength='2'); zoom: 1; } 

shadow 滤镜有三个参数,分别是阴影颜色、阴影偏移角度和阴影长度,其中阴影偏移角度需要通过计算才能获得,在例子中是 “135” 度。如果你习惯了使用偏移值设置阴影,可以使用另一个滤镜 dropshadow ,具体写法如下:

#example-ie {filter: progid:DXImageTransform.Microsoft.DropShadow(OffX='1', OffY='1', Color='#d8d8d8', Positive='true'); zoom: 1; }

效果如下:

dropshadow 有四个参数,分别是阴影 x 轴偏移、阴影 y 轴偏移、阴影颜色、最后一个 positive 属性则决定是否只为非透明像素建立可见的投影,默认值为 true ,即只为非透明像素建立阴影,若为 false ,则也为透明像素建立投影。

以上两个滤镜也支持多重阴影,开发者可以按如下方式编写,但实际效果会远差于 text-shadow 。

/* IE 下多重阴影 */
#example-ie-muti {filter: DropShadow(OffX='1', OffY='1', Color='#c10ccc', Positive='true') DropShadow(OffX='1', OffY='1', Color='#648cb4', Positive='true') DropShadow(OffX='1', OffY='1', Color='#cc150c', Positive='true'); zoom: 1; }

另外,在使用以上两个滤镜时,还有几点需要注意的:

  • 如果元素同时设置了背景色,那么以上两个滤镜将会失效,这是因为 shadow 滤镜没有像 CSS 滤镜那样区分文字阴影和容器阴影,当开发者为元素设置背景色后,IE 会自动为该元素添加阴影而取消其中文字的阴影。具体会有一个复杂的机制处理这个过程,下面会另作说明。
  • 阴影颜色需要使用形如“#aabbcc”这样的写法,不能使用“#abc”这样的简写,若使用简写,则会自动使用黑色作为阴影颜色而忽略指定的颜色,并且阴影距离也不可控(不采用指定值)。
  • 要使到多重阴影有效,元素必须触发 hasLayout ,最常用的是设置 zoom: 1 或指定元素高度、宽度。另外在 IE7 及以下版本的 IE 中,使用单个滤镜也需要触发元素的 hasLayout 。关于 hasLayout ,详细的情况可以浏览这篇文章

2. box-shadow

box-shadow 用于为容器设置阴影,其参数相对 text-shadow 要复杂一些,具体如下:

语法:box-shadow : inset || offset-x || offset-y || blur-radius || spread-radius || color

各参数分别代表是否内阴影、阴影 x 轴偏移、阴影 y 轴偏移、模糊效果作用半径、阴影伸展长度,其中 inset 、blur 和 spread 是可选的参数,与 text-shadow 中的 opacity 相似,blur 默认值为 0 ,即不产生模糊,而 spread 则比较特别,这个参数常常被开发者忽略,实际上它很有用处,spread 默认为 0 ,最常用的用法是以 blur 取值的负值为自身值做出单边阴影效果(即阴影扩展长度等于模糊长度,但是为负数,可以抵消模糊值),inset 则决定是否采用内阴影。

/* For box-shadow */
#example-box {box-shadow: 2px 2px 2px #565656; }

效果如下:

下面再补充一个利用扩展参数制作的“单边阴影”例子:

/* For box-shadow 单边阴影 */
#example-box-spread {box-shadow: 0 8px 6px -6px #565656; }

效果如下:

box-shadow-spread

内阴影例子:

/* For box-shadow 内阴影 */
#example-box-inset {box-shadow: inset 2px 2px 2px 1px #565656; }

这里必须补充一点:最新版本的现代浏览器,包括 Chrome 、 Firefox 、 Safari 、 Opera 都已经支持 box-shadow 了。但旧版本的 Opera 并不支持 box-shadow ,而 Chrome 、 Firefox 和 Safari 也需要通过各自的私有属性支持 box-shadow 。因此,为了尽可能的使到实际使用的阴影被浏览器支持,Kayo 建议开发者需要同时使用以下几个语句来为元素添加阴影(以内阴影例子说明):

/* For box-shadow 内阴影 */
#example-box-inset {
	-webkit-box-box-shadow: inset 2px 2px 2px 1px #565656;
	-moz-box-box-shadow: inset 2px 2px 2px 1px #565656;
	box-shadow: inset 2px 2px 2px 1px #565656;
}

效果如下:

虽然稍有复杂,不过相对使用图片的方法实现阴影,使用 box-shadow 已经很方便了。这时我们再回到 IE 上,上面叙述过,IE 中并不区分 text-shadow 和 box-shadow ,容器阴影也是使用 shadow 和 dropshadow 滤镜产生,但是这两个滤镜中并没有控制最终输出文字阴影还是容器阴影的参数,那么具体的情况是怎样的呢?实际上,IE 内部有一个机制处理输出什么阴影,上面有提到过,当元素设置了背景时,文字阴影会失效并改变为容器阴影,这是机制的一部分,实际上元素显示文字阴影还是容器阴影是由元素是否定义了 background 和 border 属性共同决定,具体的情况可以浏览下表:

正如上表所示,这个机制并不是那么的灵活,在实际开发时会遇到很多限制,因此,开发者更应该考虑渐进增强的设计,把阴影利用在增强效果时直接摒弃 IE 。

二. 浏览器支持

下面分开讨论浏览器对 text-shadow 和 box-shadow 的支持情况

1. text-shadow

如上面所述,IE 不支持 text-shadow ,需要通过私有滤镜达到阴影效果,因此这里列举的是现代浏览器对 text-shadow 的支持情况。

Chrome 2.0+ , Firefox 3.5+ , Safari 1.1+ 和 opera 9.5+

以上是浏览器基本支持 text-shadow 时的版本号,具体的支持情况略有不同,例如,多层阴影以及 CSS3 多层阴影渲染顺序在 Safari 4.0+ 才得到支持,Opera 9.5 使用的也是 CSS2 的多层阴影渲染顺序,模糊半径也被限制到 100px 以内。

2. box-shadow

Chrome 2.0+ , Firefox 3.5+ , Safari 4+ , Opera 10.60+ 和 IE9+

三. 完整 Demo

关于上面的例子,可以参考完整 Demo

]]>
https://kayosite.com/css3-shadow-intro.html/feed 9 2832