Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

10、PostCSS #11

Open
CodingMeUp opened this issue Nov 17, 2017 · 3 comments
Open

10、PostCSS #11

CodingMeUp opened this issue Nov 17, 2017 · 3 comments

Comments

@CodingMeUp
Copy link
Owner

CodingMeUp commented Nov 17, 2017

1. 它本质上是一个什么东西?

直观的理解为: 平台 我们直接用它,感觉不能干什么事情,但是如果让一些插件在它上面跑,那么将会很强大。css -> css parser -> plugin system -> stringify -> css

组成

  • CSS Parset
  • CSS 节点树API
  • source map 生产
  • 节点树串
@CodingMeUp
Copy link
Owner Author

2. 它能解决我们什么问题?它是通过什么方式来解决我们的问题?

能够为 CSS 提供额外的功能;

通过在 PostCSS 这个平台上,我们能够开发一些插件,来处理我们的CSS,比如热门的:autoprefixer

@CodingMeUp
Copy link
Owner Author

3、优势及SASS LESS STYLUS比较

比如,我们用 SASS 来处理 box-shadow 的前缀,我们需要这样写:

/* CSS3 box-shadow */
@mixin box-shadow($top, $left, $blur, $size, $color, $inset: false) {
    @if $inset {
        -webkit-box-shadow: inset $top $left $blur $size $color;
        box-shadow: inset $top $left $blur $size $color;
    } @else {
        -webkit-box-shadow: $top $left $blur $size $color;
        box-shadow: $top $left $blur $size $color;
    }
}

使用 PostCSS 我们只需要按标准的 CSS 来写就行了,因为最后 autoprefixer 会帮我们做添加这个事情~

box-shadow: 0 0 3px 5px rgba(222, 222, 222, .3);

未来编码的问题。实际上,PostCSS 改变的是一种开发模式。

SASS等工具:源代码 -> 生产环境 CSS
PostCSS:源代码 -> 标准 CSS -> 生产环境 CSS

这样能体会出优势吧,但是目前大家都是 SASS + PostCSS 这样的开发模式,其实我认为是不错的,取长补短嘛,当然,在 PostCSS 平台上都是可以做到的,只是目前这个过渡期

@CodingMeUp
Copy link
Owner Author

CodingMeUp commented Nov 17, 2017

4、 富哥使用的postcss-flexible 及 其他的应用

'use strict';

var postcss = require('postcss')

var valueRegExp = /(dpr|rem|url)\((.+?)(px)?\)/
var dprRegExp = /dpr\((\d+(?:\.\d+)?)px\)/
var urlRegExp = /url\(['"]?\S+?@[1-3]x\S+?['"]?\)/

module.exports = postcss.plugin('postcss-flexible', function (options) {
  if (!options) {
    options = {}
  }

  return function (root, result) {
    var desktop = !!options.desktop
    var baseDpr = options.baseDpr || 2
    var remUnit = options.remUnit || 75
    var remPrecision = options.remPrecision || 6
    var addPrefixToSelector = options.addPrefixToSelector || function (selector, prefix) {
      if (/^html/.test(selector)) {
        return selector.replace(/^html/, 'html' + prefix)
      }
      return prefix + ' ' + selector
    }

    // get calculated value of px or rem
    function getCalcValue (value, dpr) {
      var valueGlobalRegExp = new RegExp(valueRegExp.source, 'g')

      function getValue(val, type) {
        val = parseFloat(val.toFixed(remPrecision)) // control decimal precision of the calculated value
        return val == 0 ? val : val + type
      }

      return value.replace(valueGlobalRegExp, function ($0, $1, $2) {
        if ($1 === 'url') {
          if (dpr) {
            return 'url(' + $2.replace(/@[1-3]x/g, '@' + dpr + 'x') + ')'
          }
        } else if ($1 === 'dpr') {
          if (dpr) {
            return getValue($2 * dpr / baseDpr, 'px')
          }
        } else if ($1 === 'rem') {
          return getValue($2 / remUnit, 'rem')
        }
        return $0
      })
    }
    
    function handleDesktop (rule) {
      rule.walkDecls(function (decl) {
        if (valueRegExp.test(decl.value)) {
          if (decl.value === '0px') {
            decl.value = '0'
          } else {
            if (dprRegExp.test(decl.value) || urlRegExp.test(decl.value)) {
              decl.value = getCalcValue(decl.value, 2)
            } else {
              // only has rem()
              decl.value = getCalcValue(decl.value)
            }
          }
        }
      })
    }
    
    function handleMobile (rule) {
      if (rule.selector.indexOf('[data-dpr="') !== -1) {
        return
      }

      var newRules = []
      var hasDecls = false
      
      for (var dpr = 3; dpr >= 1; dpr--) {
        var newRule = postcss.rule({
          selectors: rule.selectors.map(function (sel) {
            return addPrefixToSelector(sel, '[data-dpr="' + dpr + '"]')
          }),
          type: rule.type
        })
        newRules.push(newRule)
      }

      rule.walkDecls(function (decl) {
        if (valueRegExp.test(decl.value)) {
          if (decl.value === '0px') {
            decl.value = '0'
          } else {
            if (dprRegExp.test(decl.value) || urlRegExp.test(decl.value)) {
              // generate 3 new decls and put them in the new rules which has [data-dpr]
              newRules.forEach(function (newRule, index) {
                var newDecl = postcss.decl({
                  prop: decl.prop,
                  value: getCalcValue(decl.value, 3 - index)
                })
                newRule.append(newDecl)
              })
              hasDecls = true
              decl.remove() // delete this rule
            } else {
              // only has rem()
              decl.value = getCalcValue(decl.value)
            }
          }
        }
      })

      if (hasDecls) {
        newRules.forEach(function (newRule) {
          rule.parent.insertAfter(rule, newRule)
        })
      }

      // if the origin rule has no declarations, delete it
      if (!rule.nodes.length) {
        rule.remove()
      }
    }

    root.walkRules(function (rule) {
      desktop ? handleDesktop(rule) : handleMobile(rule)
    })
  }
})

rem px 转换

加入 processors 就可以用了,很方便:

var custom = function(css, opts){
    css.eachDecl(function(decl){
        decl.value = decl.value.replace(/\d+rem/, function(str){
            return 16 * parseFloat(str) + "px";
        });
    });
};

with webpack vue

const vueLoaderOptions = {
  postcss: pack => {
    // see: https://github.com/ai/browserslist#queries
    const browsers = 'Android >= 4, iOS >= 7, IE >= 10'

    return [
      require('postcss-import')({
        path: paths.src('application/styles')
      }),
      require('postcss-url')({
        basePath: paths.src('static')
      }),
      require('postcss-cssnext')({
        browsers,
        features: {
          customProperties: {
            variables: require(paths.src('application/styles/variables'))
          },
          // 禁用 autoprefixer,在 postcss-rtl 后单独引入
          // 否则会跟 postcss-rtl 冲突
          autoprefixer: false
        }
      }),
      // 如果不需要 flexible,请移除
      require('postcss-flexible')({
        remUnit: 75
      }),
      require('autoprefixer')({
        browsers
      }),
      require('postcss-browser-reporter')(),
      require('postcss-reporter')()
    ]
  },
  autoprefixer: false
}

   =====
  webpackConfig.plugins.push(
    new webpack.LoaderOptionsPlugin({
      minimize: true,
      options: {
        context: __dirname
      },
      vue: vueLoaderOptions
    }),

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant