ecomfe / esui

enterprise simple ui library
https://ecomfe.github.io/esui-family/
342 stars 194 forks source link

关于引入Icon Font的方案 #369

Closed otakustay closed 9 years ago

otakustay commented 10 years ago

ESUI有计划使用Icon Font来代替图片(当然不会影响向后兼容性,我们会做一套新的皮肤),面对这一场景,我们需要满足以下需求:

  1. 默认在edp import esui后能直接使用,即ESUI必须有一个自带的或者依赖的字体
  2. 允许使用方使用自定义的字体,来覆盖掉ESUI的默认

对于默认,现在的计划是直接上FontAwesome,不再纠结啥啥项目要什么样了,因此可以满足第1点。

对于第2点,我个人想法如下:

  1. ESUI建立一个变量esui-icon-prefix,默认值就是fa了保持和FontAwesome一样
  2. ESUI在需要图标的地方,可以使用this.helper.addIconClass('magnifier')来通过JS生成class,也可以用.xxx:before { .@{esui-icon-prefix}-magnifier() }来当mixin用(不知道能不能样搞,不能的话想别的办法)
  3. 对于各种图标,按照FontAwesome的规则来定义class的名字,如放大镜就叫magnifier,三角就叫triangle
  4. 当有需要使用别的字体时,需要定义一个新的less,里面各种图标的名字需要和FontAwesome一样,比如放大镜也必须叫magnifier不能叫glass

以上方案能解决问题,就是使用其它字体时,要写一个less可能不是那么方便,但想不出别的方法了

对于一个系统,我们推荐不要FontAwesome和别的字体混用,ESUI会用到的是FontAwesome的一部分,推荐使用其它字体时在字体中能覆盖这些,用2个字体文件没啥收益

@Exodia @bjlxj2008 @yankun01 @Justineo @wurongyao

yankun01 commented 10 years ago

立理说的这个是个办法, 我能想到另外一个办法就是,在esui中维护一个map关系。然后在需要替换的时候把这个map关系覆盖掉。

比如说: esui中有缺省定义 icons = { 'magnifier': 'fa-xxx', 'arrow-up': 'fa-arrow-up' } 我们在render html的时候可以写icons.magnifier 来调用,在需要替换的时候把这组map替换一下。

这样用户可以灵活的替换esui中的图标,也不用固定一个this.helper.addIconClass('magnifier')来受到限制。

听听大家的建议。

otakustay commented 10 years ago

但是就不可以用为元素了吗?

在 2014年10月8日,上午9:36,yankun01 notifications@github.com 写道:

立理说的这个是个办法, 我能想到另外一个办法就是,在esui中维护一个map关系。然后在需要替换的时候把这个map关系覆盖掉。

比如说: esui中有缺省定义 icons = { 'magnifier': 'fa-xxx', 'arrow-up': 'fa-arrow-up' } 我们在render html的时候可以写icons.magnifier 来调用,在需要替换的时候把这组map替换一下。

这样用户可以灵活的替换esui中的图标,也不用固定一个this.helper.addIconClass('magnifier')来受到限制。

听听大家的建议。

— Reply to this email directly or view it on GitHub.

yankun01 commented 10 years ago

感觉伪元素还是可以用的,只要确定添加class的DOM就可以了。

otakustay commented 10 years ago

我的意思是,如果用mixin的形式用在伪元素上,似乎就搞不了?

ui-xxx-bar:after {
    .icon-magnifier();
}
otakustay commented 10 years ago

@Justineo 关于控件皮肤定制化和IconFont的关系,业界有比较好的解决方案吗

Justineo commented 10 years ago

刚去整理了一下最流行的几个框架的情况:

常见框架的图标组件:

Framework Iconfont Usage
Foundation Foundation Icon Fonts <i class="fi-[icon]"></i>
Bootstrap Glyphicons <span class="glyphicon glyphicon-[icon]"></span>
UIkit FontAwesome <i class="uk-icon-[icon]"></i>

注:


UIkit 那种做法相当于自己定义一套描述 icon 的词汇表,这样的好处是切换一套图标不用改 HTML,只需要改 CSS 的 icon mapping(相当于对 icon font 组件的 API 进行了一层封装,没有在调用时——写 HTML 时——直接调第三方的 API)。

原 issue 的意思是说我们在这一层选择和 FA 一样的接口,不再自定一套。如果我们真的要选另一套 icon font 方案,就得写一个 FA 词汇表到其他项目样式(content 属性对应字符)的映射。

另外,各个项目采取的都是空标签 + className 的方式。

otakustay commented 10 years ago

@yankun01 我比较倾向UIkit的做法,有现实存在的库作为参考也更加能确保可行性

yankun01 commented 10 years ago

@otakustay 同意UIkit的办法。

跟之前讨论的基本一致。 我们要提供自己的mapping。 将来业务系统提供自己的图标映射。

另外我也比较倾向@Justineo提到的,普通icon用空标签+className的做法。之前我们的结论是有事件行为的需要用空标签,没有的就用伪元素。后来考虑了一下,或许我们应该统一下。

otakustay commented 10 years ago

UIkit和你的做法的不同在于映射是在CSS中实现而非JS,我也倾向不要在JS中去做这个映射

对于icon是否用标签的问题,我们也讨论过多次,用标签最大的问题是动态生成DOM结构时会比较麻烦,如Button是否需要根据iconBeforeiconAfter属性是否存在,是否有值等一系列条件去判断是否要生成2个元素,这2个属性变化时又是否要再去移除元素,这个是否有好的解决方案?

yankun01 commented 10 years ago

我明白灰大的concern。 其实我个人理解伪元素的解决方案唯一不爽的地方就是不统一。有些地方用了伪元素,为了一些DOM事件,有些地方又不得不用空元素。

刚想到多一个标签其实还有一个灵活的地方是可以使用动画之类的CSS。 比如说我点击按钮之后要来一个load的旋转, <span class="animate-spin icon-user"></span> animate-spin中可以定义一些frame来做CSS动画。 如果用伪元素,就要用mixin或extend之类的方式来扩展一下了。

个人感觉空元素比伪元素更灵活些,需要的就是我们要接受一个icon元素在这里。

至于重绘过程中需要添加生成元素,其实这个到还可以接受。很多属性变化也会引起DOM的增减。

otakustay commented 10 years ago

我接受一个icon放在那没问题,我只是想知道这个元素怎么去生成,是要很多if分支去根据属性不同来生成,还是怎么样,有没有方便的实现方法

yankun01 commented 10 years ago

理解了。初步想一下。

一个办法就是在原始DOM里面直接写好了,然后ESUI在初始化的时候拷贝一份。 `

` 另外一个只能通过属性来判断生成了。

otakustay commented 10 years ago

那么这样,我的结论如下:

关于不同字体库的桥接

使用一个less的map来处理,类似UIkit的方案,不使用JavaScript控制这一映射关系

关于使用元素放置图标

统一使用<span>元素放置图标,对于纯视觉作用的图标元素必须符合以下要求:

  1. icon-xxx的part id和class,其中xxx指的是图标元素代表的意义,如前置图标为icon-before,如果只有一个图标那就没有-xxx部分
  2. 元素无内容
  3. 当无此图标时,移除元素,有此图标时生成元素
  4. 使用painter来处理控制上面一条的逻辑

对于有交互作用的但视觉上暂时设计为图标的元素,保持以交互和逻辑为优先选择合适的part id、元素类型等,如<div>元素配合dropdown-toggle-area的part id等

是否可行?

Justineo commented 10 years ago

使用那段不是很明白,如果 xxx 指代元素代表的意义,前置图标不应该是直接写 <esui-button><span class="icon-add"></span>添加</esui-button> 这样的么?

otakustay commented 10 years ago

对于有意义的元素,这元素从本质上来说就不是“图标”,上面那贴特指的是“由用户指定控件在视觉上添加的图标”,也就是可以使用纯CSS通过伪元素实现的那些场景

对于有实际交互意义的图标,还是建议按标准的交互场景和逻辑去写part id以及内容,并寻找合适的元素,也不仅限于<span>,该是啥就是啥

我修改了一下上面的回复

Justineo commented 10 years ago

我不是这个意思,只是没看懂为啥有 icon-before

otakustay commented 10 years ago

比如按钮,允许用户自定义文字前的图标,也允许自定义文字后的图标,但这2图标本身就是纯视觉,所以会有icon-before表示前置图标,icon-after表示后置图标

以前我们用伪元素实现这个,现在大家希望统一,那么我们就统一用空元素实现

Justineo commented 10 years ago

那其实是 <esui-button><span class="icon-before icon-add></span> 添加</esui-button> 这样吧?

还是说 icon-add 不写,样式里再写类似这样的代码:

.ui-button .icon-before {
    .icon(add);
}
yankun01 commented 10 years ago

上几天我让 @iamweilee 模仿uikit搞了一下。 https://github.com/yankun01/esui/blob/3.1.0-dev/src/css/standard/fa-icons.less

他提交了一些代码。 大家看看一起讨论一下吧。

otakustay commented 10 years ago

好吧,这样来看上面说得不免详细,应该是这样的,假设是上面说的场景,那么设计就这样:

  1. Button暴露{string} iconBefore
  2. 如果iconBefore有值,则生成<span id="{id}-icon-before" class="ui-button-icon-before icon icon-{iconBefore}"></span>这样的元素

这个元素有以下特征:

  1. 元素是<span>
  2. 里面没内容
  3. 有icon-before这个part id和part class,对应的是暴露在外的属性
  4. 通常此类图标是能让用户自定义的,根据用户给的值添加一个icon相关的class显示出正确的图标
yankun01 commented 10 years ago

个人觉得也可以用类似于: <button ui-type=“Button”><span class="ui-icon-user"></span> 文字</button>

otakustay commented 10 years ago

出于要能找到这个元素的考虑,我认为加一个part id是必须的,所以有上面的特征规范

这个ui-icon-user就是当用户指定iconBefore的值为user时才多出来的

Justineo commented 10 years ago

好,那没问题了。按 ESUI 里面 part 的通用方式来搞。用户指定一个 data-ui-icon-before="user" 就好了。

Justineo commented 10 years ago

PS: 应该不会出现需要前面放两个图标或者文字中间放个图标的情况吧……

yankun01 commented 10 years ago

赞,多了些配置项,效果是一样的。

这个放俩图标有点夸张了。 到底这个button是代表啥意思呢?

yankun01 commented 9 years ago

最近在开发过程中遇到一些问题, 继续在这里跟大家讨论一下 。

之前考虑的是在esui中放一个fa.less文件。里面包含FontAwesome图标的定义。 例如: ·.@{ui-class-prefix}-icon-glass:before { content: "\f000"; }·

如果需要 更换图标的时候直接不引用fa.less,引用另外一个就可以了。

现在遇到一个问题是: 其他的项目也用到了图标,就要从esui中引用。 感觉有些不合理。 现在我感觉也许是个时机把font单独拉出来做一个项目。 然后业务系统引用这个项目了。

形式也许可以提供less变量的形式。 例如: font-family: @font-family-name; ·.@{ui-class-prefix}-icon-glass:before { content: "@glass-font-code"; }

不同的字体文件暴露为一个变量的覆盖。 @font-face { font-family: 'FontAwesome'; src: url("@{esui-fa-icon-font-path}/fontawesome-webfont.eot"); src: url("@{esui-fa-icon-font-path}/fontawesome-webfont.eot?#iefix") format("embedded-opentype"), url("@{esui-fa-icon-font-path}/fontawesome-webfont.woff") format("woff"), url("@{esui-fa-icon-font-path}/fontawesome-webfont.ttf") format("truetype"); font-weight: normal; font-style: normal; } @font-family-name: 'fontawesome'; @glass-font-code: \u1234;