├── .eslintrc.js ├── .github └── workflows │ └── docs.yml ├── .gitignore ├── .husky └── pre-commit.txt ├── .lintstagedrc.json ├── .markdownlint-cli2.jsonc ├── .markdownlint.jsonc ├── .nvmrc ├── .prettierignore ├── LICENSE ├── README.md ├── deploy.sh ├── docs ├── .vuepress │ ├── components │ │ └── hide-outbound.vue │ ├── config.ts │ ├── configs │ │ ├── index.ts │ │ ├── navbar │ │ │ ├── index.ts │ │ │ └── zh.ts │ │ └── sidebar │ │ │ ├── index.ts │ │ │ └── zh.ts │ ├── public │ │ ├── hero.png │ │ ├── icons │ │ │ ├── android-chrome-192x192.png │ │ │ ├── android-chrome-512x512.png │ │ │ ├── apple-touch-icon-120x120.png │ │ │ ├── apple-touch-icon-152x152.png │ │ │ ├── apple-touch-icon-180x180.png │ │ │ ├── apple-touch-icon-60x60.png │ │ │ ├── apple-touch-icon-76x76.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── logo.svg │ │ │ ├── msapplication-icon-144x144.png │ │ │ ├── mstile-150x150.png │ │ │ └── safari-pinned-tab.svg │ │ └── manifest.json │ └── styles │ │ └── index.styl ├── README.md ├── REGEXP │ ├── README.md │ └── images │ │ ├── regex.jpg │ │ └── regexper.png ├── _images │ ├── box-model-example.png │ ├── css-grayscale-example.png │ ├── event_loop.gif │ ├── git-merge-difference.png │ ├── koa-middleware.png │ ├── libuv.jpeg │ ├── youtube.png │ └── z-index-stacking-level.png ├── dev-ops.md ├── develop │ ├── README.md │ ├── css │ │ ├── README.md │ │ ├── design │ │ │ ├── botton │ │ │ │ ├── css │ │ │ │ │ ├── reset.css │ │ │ │ │ └── styles.css │ │ │ │ └── index.html │ │ │ └── images │ │ │ │ ├── auto-width.gif │ │ │ │ ├── flexbox-1.gif │ │ │ │ └── flexbox-2.gif │ │ ├── images │ │ │ ├── anima-loading.gif │ │ │ ├── avatar-1.png │ │ │ ├── background-more.png │ │ │ ├── drawing_graphics.png │ │ │ ├── image-hover.gif │ │ │ ├── nav-anima.png │ │ │ ├── nav-split.png │ │ │ └── wildcard.png │ │ ├── reset.css │ │ └── theory.md │ ├── html │ │ └── README.md │ ├── javascript │ │ ├── README.md │ │ ├── jq │ │ │ └── jquery-back-top.js │ │ ├── libs.md │ │ ├── mini-program.md │ │ ├── nodejs.md │ │ ├── react.md │ │ ├── typescript.md │ │ ├── utlis.js │ │ └── vue.md │ ├── mobile │ │ └── README.md │ └── solution.md ├── further │ ├── README.md │ ├── books.md │ ├── en.md │ ├── glossary.md │ ├── guide │ │ └── js.md │ └── links.md ├── git.md ├── hg.md ├── jira.md └── topic │ ├── DSA.md │ ├── README.md │ ├── browser.md │ ├── complex.md │ ├── css.md │ ├── html.md │ ├── images │ ├── browse-http-request.png │ ├── dom-render-process.png │ ├── dom-tree.png │ ├── event-loop.png │ ├── http2-stack-vs-http3-stack.png │ ├── mvvm-design.png │ ├── react.jpg │ ├── reconciliation.png │ ├── tcp-1.png │ ├── tcp-2.png │ ├── vue-lifecycle-v3.svg │ ├── vue-lifecycle.png │ ├── vuejs.jpg │ └── websocket-connect.png │ ├── js.md │ ├── network.md │ ├── nodejs.md │ ├── performance.md │ ├── react.md │ ├── vue.md │ └── webpack.md ├── package.json ├── tsconfig.base.json ├── tsconfig.json └── yarn.lock /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: "plugin:markdown/recommended", 3 | }; 4 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: docs 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | workflow_dispatch: 8 | 9 | jobs: 10 | docs: 11 | runs-on: ubuntu-latest 12 | 13 | env: 14 | DOCS_GA_ID: 15 | NODE_VERSION: '20' 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | with: 20 | # “最近更新时间” 等 git 日志相关信息,需要拉取全部提交记录 21 | fetch-depth: 0 22 | 23 | # - name: Install pnpm 24 | # uses: pnpm/action-setup@v2 25 | # with: 26 | # # 选择要使用的 pnpm 版本 27 | # version: 7 28 | # # 使用 pnpm 安装依赖 29 | # run_install: true 30 | 31 | - name: Setup Node.js 32 | uses: actions/setup-node@v3 33 | with: 34 | node-version: ${{ env.NODE_VERSION }} 35 | # cache: pnpm 36 | 37 | # - name: Install dependencies 38 | # run: pnpm install --frozen-lockfile 39 | 40 | # 运行构建脚本 41 | - name: Build documentation site 42 | run: yarn && yarn build 43 | 44 | # 查看 workflow 的文档来获取更多信息 45 | # @see https://github.com/crazy-max/ghaction-github-pages 46 | - name: Deploy to GitHub Pages 47 | uses: crazy-max/ghaction-github-pages@v2.2.0 48 | with: 49 | target_branch: gh-pages 50 | build_dir: docs/.vuepress/dist 51 | env: 52 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 编辑器配置 2 | .vscode 3 | 4 | # 本地临时文件 5 | buffer 6 | 7 | # 本地依赖 8 | node_modules 9 | 10 | docs/.vuepress/dist/** 11 | 12 | .cache 13 | .temp 14 | -------------------------------------------------------------------------------- /.husky/pre-commit.txt: -------------------------------------------------------------------------------- 1 | npx lint-staged 2 | -------------------------------------------------------------------------------- /.lintstagedrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "!*.md": "prettier --ignore-unknown --write", 3 | "*.md": [ 4 | "markdownlint-cli2 --fix", 5 | "prettier --write" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.markdownlint-cli2.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "extends": "./.markdownlint.jsonc", 4 | }, 5 | "customRules": ["markdownlint-rule-search-replace"], 6 | "ignores": ["node_modules", ".git", ".github", "tests"], 7 | } 8 | -------------------------------------------------------------------------------- /.markdownlint.jsonc: -------------------------------------------------------------------------------- 1 | // This file defines our configuration for Markdownlint. See 2 | // https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md 3 | // for more details on each rule. 4 | 5 | { 6 | "default": true, 7 | // Disabled, as some callouts include headings. 8 | "heading-increment": false, 9 | "ul-style": { 10 | "style": "dash", 11 | }, 12 | "ul-indent": { 13 | "indent": 2, 14 | }, 15 | "no-hard-tabs": { 16 | "spaces_per_tab": 2, 17 | }, 18 | "line-length": false, 19 | "no-duplicate-heading": { 20 | "siblings_only": true, 21 | }, 22 | "single-title": { 23 | "front_matter_title": "^\\s*title\\s*[:=]", 24 | }, 25 | "no-trailing-punctuation": { 26 | "punctuation": ".,;:", 27 | }, 28 | // Consecutive Notes/Callouts currently don't conform with this rule 29 | "no-blanks-blockquote": false, 30 | // Force ordered numbering to catch accidental list ending from indenting 31 | "ol-prefix": false, 32 | "no-inline-html": { 33 | "allowed_elements": [ 34 | "a", 35 | "abbr", 36 | "annotation", 37 | "br", 38 | "caption", 39 | "code", 40 | "col", 41 | "colgroup", 42 | "dd", 43 | "details", 44 | "div", 45 | "dl", 46 | "dt", 47 | "em", 48 | "h4", 49 | "h5", 50 | "img", 51 | "kbd", 52 | "li", 53 | "math", 54 | "menclose", 55 | "mfenced", 56 | "mfrac", 57 | "mfrac", 58 | "mi", 59 | "mmultiscripts", 60 | "mn", 61 | "mo", 62 | "mover", 63 | "mphantom", 64 | "mprescripts", 65 | "mroot", 66 | "mrow", 67 | "ms", 68 | "mspace", 69 | "mspace", 70 | "msqrt", 71 | "mstyle", 72 | "msub", 73 | "msubsup", 74 | "msup", 75 | "mtable", 76 | "mtd", 77 | "mtext", 78 | "mtr", 79 | "munder", 80 | "munderover", 81 | "none", 82 | "ol", 83 | "p", 84 | "pre", 85 | "q", 86 | "section", 87 | "semantics", 88 | "strong", 89 | "sub", 90 | "summary", 91 | "sup", 92 | "table", 93 | "tbody", 94 | "td", 95 | "tfoot", 96 | "th", 97 | "thead", 98 | "tr", 99 | "ul", 100 | "var", 101 | "iframe", 102 | "h1", 103 | ], 104 | }, 105 | "first-line-heading": false, 106 | "no-emphasis-as-heading": false, 107 | "no-bare-urls": false, 108 | // Produces too many false positives 109 | "no-space-in-emphasis": false, 110 | "fenced-code-language": true, 111 | // See https://github.com/mdn/content/pull/20026, as macros currently break this 112 | "no-empty-links": false, 113 | "code-block-style": { 114 | "style": "fenced", 115 | }, 116 | "emphasis-style": { 117 | "style": "underscore", 118 | }, 119 | "strong-style": { 120 | "style": "asterisk", 121 | }, 122 | // Disabled, as yari generates link fragments by replacing spaces with underscores, not dashes. 123 | "link-fragments": false, 124 | 125 | // https://github.com/OnkarRuikar/markdownlint-rule-search-replace 126 | "search-replace": { 127 | "rules": [ 128 | { 129 | "name": "curly-single-quotes", 130 | "message": "Don't use curly single quotes", 131 | "searchPattern": "/‘|’/g", 132 | "replace": "'", 133 | "searchScope": "text", 134 | }, 135 | { 136 | "name": "trailing-spaces", 137 | "message": "Avoid trailing spaces", 138 | "searchPattern": "/ +$/gm", 139 | "replace": "", 140 | "searchScope": "all", 141 | }, 142 | { 143 | "name": "double-spaces", 144 | "message": "Avoid double spaces", 145 | "searchPattern": "/([^\\s>]) ([^\\s|])/g", 146 | "replace": "$1 $2", 147 | "searchScope": "text", 148 | }, 149 | ], 150 | }, 151 | } 152 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v18.17 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | docs/.vuepress/dist/** -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Web Lab

2 | 3 |

4 | 5 | GitHub stars 6 | GitHub forks 8 | GitHub watchers 10 | CRAN/METACRAN 12 |

13 | 14 |

15 | Website · 16 | 目录概览 17 |

18 | 19 | > :art: 记录 Web 领域的研究与实践 20 | 21 | ## Start 22 | 23 | ```shell 24 | # 本地开发 25 | yarn start 26 | 27 | # 生成文档 28 | yarn build 29 | ``` 30 | 31 | ## Branch 32 | 33 | | Branch | Description | 34 | | ------- | ---------------------------------------------------------------------- | 35 | | master | 主/文档分支。编写笔记在此分支进行更新 | 36 | | develop | 开发分支。项目构建类先在开发分支进行,开发完毕后再合并至 master 分支中 | 37 | 38 | ## commit type 39 | 40 | | Type | Description | 41 | | -------- | ---------------- | 42 | | `docs:` | 编写文档 | 43 | | `build:` | website 配置相关 | 44 | | `ci:` | CI 配置相关 | 45 | 46 | 由于更多情况是编写文档,还可以约定 emoji 来增强 commit message 的语义: 47 | 48 | | emoji | code | Description | 49 | | --------- | ----------- | ---------------------- | 50 | | :pencil2: | `:pencil2:` | 编写文档 (README 相关) | 51 | | :art: | `:art:` | 润色/完善内容 | 52 | | :truck: | `:truck:` | 内容拆分或重构 | 53 | 54 | ## 专栏与博客 55 | 56 | - [anran758's homepage](https://anran758.github.io/blog/): web 相关的效果展示页 57 | - [anran758's blog](https://anran758.github.io/blog/): 业务场景的分析与解决方案、计算机相关的笔记、简单的教程等。 58 | - [专栏 | 初级前端工程师的进阶之路](https://zhuanlan.zhihu.com/c_1147180666474176512): 专门针对初级工程师进阶时常遇到的一些问题专辑。 59 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 确保脚本抛出遇到的错误 4 | set -e 5 | 6 | # 生成静态文件 7 | npm run build 8 | 9 | # 进入生成的文件夹 10 | cd docs/.vuepress/dist 11 | 12 | # 如果是发布到自定义域名 13 | # echo 'www.example.com' > CNAME 14 | 15 | git init 16 | git add -A 17 | git commit -m 'deploy' 18 | 19 | # 如果发布到 https://.github.io 20 | # git push -f git@github.com:/.github.io.git master 21 | 22 | # 如果发布到 https://.github.io/ 23 | # git push -f git@github.com:/.git master:gh-pages 24 | git push -f git@github.com:anran758/front-end-lab.git master:gh-pages 25 | 26 | cd - 27 | -------------------------------------------------------------------------------- /docs/.vuepress/components/hide-outbound.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /docs/.vuepress/config.ts: -------------------------------------------------------------------------------- 1 | import { defineUserConfig } from '@vuepress/cli'; 2 | import { path } from '@vuepress/utils'; 3 | import { googleAnalyticsPlugin } from '@vuepress/plugin-google-analytics'; 4 | import { registerComponentsPlugin } from '@vuepress/plugin-register-components'; 5 | import { pwaPlugin } from '@vuepress/plugin-pwa'; 6 | import { pwaPopupPlugin } from '@vuepress/plugin-pwa-popup'; 7 | import { viteBundler } from '@vuepress/bundler-vite'; 8 | import { webpackBundler } from '@vuepress/bundler-webpack'; 9 | import { defaultTheme } from '@vuepress/theme-default'; 10 | import { searchPlugin } from '@vuepress/plugin-search'; 11 | 12 | import { navbar, sidebar } from './configs'; 13 | 14 | const isProd = process.env.NODE_ENV === 'production'; 15 | 16 | /** 17 | * @see {@link https://github.com/vuepress/vuepress-next/blob/main/docs/.vuepress/config.ts} 18 | */ 19 | export default defineUserConfig({ 20 | base: '/front-end-lab/', 21 | locales: { 22 | '/': { 23 | lang: 'zh-CN', 24 | title: 'Web 实验室', 25 | description: 'Web 开发笔记与解决方案', 26 | }, 27 | }, 28 | 29 | head: [ 30 | ['link', { rel: 'icon', href: `/icons/logo.svg` }], 31 | ['link', { rel: 'manifest', href: '/manifest.json' }], 32 | ['meta', { name: 'theme-color', content: '#3eaf7c' }], 33 | ['meta', { name: 'apple-mobile-web-app-capable', content: 'yes' }], 34 | [ 35 | 'meta', 36 | { name: 'apple-mobile-web-app-status-bar-style', content: 'black' }, 37 | ], 38 | [ 39 | 'link', 40 | { rel: 'apple-touch-icon', href: `/icons/apple-touch-icon-152x152.png` }, 41 | ], 42 | [ 43 | 'link', 44 | { 45 | rel: 'mask-icon', 46 | href: '/icons/safari-pinned-tab.svg', 47 | color: '#3eaf7c', 48 | }, 49 | ], 50 | [ 51 | 'meta', 52 | { 53 | name: 'msapplication-TileImage', 54 | content: '/icons/msapplication-icon-144x144.png', 55 | }, 56 | ], 57 | ['meta', { name: 'msapplication-TileColor', content: '#000000' }], 58 | ], 59 | 60 | bundler: 61 | // specify bundler via environment variable 62 | process.env.DOCS_BUNDLER === 'webpack' ? webpackBundler() : viteBundler(), 63 | 64 | alias: { 65 | '@image': path.resolve(__dirname, '../_images'), 66 | }, 67 | 68 | // theme: '@vuepress/vue', 69 | theme: defaultTheme({ 70 | repo: 'https://github.com/anran758/front-end-lab', 71 | editLinks: true, 72 | docsDir: 'docs', 73 | smoothScroll: true, 74 | backToTop: true, 75 | sidebarDepth: 4, 76 | displayAllHeaders: true, 77 | locales: { 78 | '/': { 79 | // navbar 80 | navbar: navbar.zh, 81 | selectLanguageName: '简体中文', 82 | selectLanguageText: '选择语言', 83 | selectLanguageAriaLabel: '选择语言', 84 | 85 | // sidebar 86 | sidebar: sidebar.zh, 87 | 88 | // page meta 89 | editLinkText: '在 GitHub 上编辑此页', 90 | lastUpdatedText: '上次更新', 91 | contributorsText: '贡献者', 92 | 93 | // custom containers 94 | tip: '提示', 95 | warning: '注意', 96 | danger: '警告', 97 | 98 | // 404 page 99 | notFound: [ 100 | '这里什么都没有', 101 | '我们怎么到这来了?', 102 | '这是一个 404 页面', 103 | '看起来我们进入了错误的链接', 104 | ], 105 | backToHome: '返回首页', 106 | 107 | // a11y 108 | openInNewWindow: '在新窗口打开', 109 | toggleDarkMode: '切换夜间模式', 110 | toggleSidebar: '切换侧边栏', 111 | }, 112 | }, 113 | themePlugins: { 114 | // only enable git plugin in production mode 115 | git: isProd, 116 | // use shiki plugin in production mode instead 117 | prismjs: !isProd, 118 | }, 119 | }), 120 | plugins: [ 121 | /** 122 | * @see https://vuepress.github.io/zh/reference/plugin/search.html#locales 123 | */ 124 | searchPlugin({ 125 | locales: { 126 | '/': { 127 | placeholder: 'Search', 128 | }, 129 | '/zh/': { 130 | placeholder: '搜索', 131 | }, 132 | }, 133 | }), 134 | 135 | pwaPlugin({}), 136 | pwaPopupPlugin({ 137 | locales: { 138 | '/': { 139 | message: 'New content is available.', 140 | buttonText: 'Refresh', 141 | }, 142 | '/zh/': { 143 | message: '发现新内容可用', 144 | buttonText: '刷新', 145 | }, 146 | }, 147 | }), 148 | 149 | googleAnalyticsPlugin({ 150 | id: 'G-F07WV60EQR', 151 | }), 152 | 153 | registerComponentsPlugin({ 154 | componentsDir: path.resolve(__dirname, './components'), 155 | }), 156 | 157 | // only enable shiki plugin in production mode 158 | // isProd ? shikiPlugin({ theme: 'dark-plus' }) : [], 159 | ], 160 | 161 | // extraWatchFiles: ['.vuepress/nav/zh.js'] 162 | }); 163 | -------------------------------------------------------------------------------- /docs/.vuepress/configs/index.ts: -------------------------------------------------------------------------------- 1 | export * as navbar from './navbar' 2 | export * as sidebar from './sidebar' 3 | -------------------------------------------------------------------------------- /docs/.vuepress/configs/navbar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './zh' 2 | -------------------------------------------------------------------------------- /docs/.vuepress/configs/navbar/zh.ts: -------------------------------------------------------------------------------- 1 | import type { NavbarConfig } from '@vuepress/theme-default'; 2 | 3 | export const zh: NavbarConfig = [ 4 | { 5 | text: 'Web 开发', 6 | link: '/develop/', 7 | }, 8 | { 9 | text: '技术要点', 10 | link: '/topic/', 11 | }, 12 | { 13 | text: '扩展阅读', 14 | link: '/further/', 15 | children: [ 16 | { 17 | text: "Anran758's Homepage", 18 | link: 'https://anran758.github.io/', 19 | }, 20 | { 21 | text: "Anran758's Blog", 22 | link: 'https://anran758.github.io/blog/', 23 | }, 24 | ], 25 | }, 26 | ]; 27 | -------------------------------------------------------------------------------- /docs/.vuepress/configs/sidebar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './zh' 2 | -------------------------------------------------------------------------------- /docs/.vuepress/configs/sidebar/zh.ts: -------------------------------------------------------------------------------- 1 | import type { SidebarConfig } from '@vuepress/theme-default'; 2 | 3 | export const zh: SidebarConfig = { 4 | '/topic/': [ 5 | { 6 | text: 'Web 技术栈', 7 | children: [ 8 | '/topic/html.md', 9 | '/topic/css.md', 10 | '/topic/js.md', 11 | '/topic/nodejs.md', 12 | ], 13 | }, 14 | { 15 | text: '开发框架与工具', 16 | children: ['/topic/react.md', '/topic/vue.md', '/topic/webpack.md'], 17 | }, 18 | { 19 | text: '优化与原理解析', 20 | children: [ 21 | '/topic/browser.md', 22 | '/topic/performance.md', 23 | '/topic/network.md', 24 | ], 25 | }, 26 | '/topic/complex.md', 27 | ], 28 | 29 | '/': [ 30 | { 31 | text: 'JavaScript 生态', 32 | children: [ 33 | '/develop/javascript/README.md', 34 | '/develop/javascript/typescript.md', 35 | '/develop/javascript/vue.md', 36 | '/develop/javascript/react.md', 37 | '/develop/javascript/nodejs.md', 38 | '/develop/javascript/mini-program.md', 39 | '/develop/javascript/libs.md', 40 | ], 41 | }, 42 | { 43 | text: 'Web 开发', 44 | children: [ 45 | '/develop/html/README.md', 46 | '/develop/css/README.md', 47 | '/develop/css/theory.md', 48 | '/REGEXP/README.md', 49 | '/develop/solution.md', 50 | ], 51 | }, 52 | { 53 | text: '项目管理', 54 | children: ['/git.md', '/hg.md', '/jira.md', '/dev-ops.md'], 55 | }, 56 | { 57 | text: '更多', 58 | children: [ 59 | '/further/glossary.md', 60 | '/further/books.md', 61 | '/further/README.md', 62 | ], 63 | }, 64 | ], 65 | }; 66 | -------------------------------------------------------------------------------- /docs/.vuepress/public/hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/.vuepress/public/hero.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/.vuepress/public/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/.vuepress/public/icons/android-chrome-512x512.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/.vuepress/public/icons/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/.vuepress/public/icons/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/.vuepress/public/icons/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/.vuepress/public/icons/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/.vuepress/public/icons/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/.vuepress/public/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/.vuepress/public/icons/favicon-16x16.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/.vuepress/public/icons/favicon-32x32.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 12 | 13 | 14 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/msapplication-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/.vuepress/public/icons/msapplication-icon-144x144.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/.vuepress/public/icons/mstile-150x150.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /docs/.vuepress/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "FrontEndWiki", 3 | "short_name": "FrontEndWiki", 4 | "icons": [ 5 | { 6 | "src": "/icons/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/icons/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "start_url": "/index.html", 17 | "display": "standalone", 18 | "background_color": "#fff", 19 | "theme_color": "#3eaf7c" 20 | } 21 | -------------------------------------------------------------------------------- /docs/.vuepress/styles/index.styl: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | --vt-font-family-base: Quotes, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; 4 | 5 | font-family: var(--vt-font-family-base); 6 | } 7 | 8 | details { 9 | margin: 1.6em 0; 10 | 11 | &[block] { 12 | display: block; 13 | position: relative; 14 | border-radius: 2px; 15 | padding: 1.6em; 16 | background-color: #eee; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | tagline: 4 | footer: GPL Licensed | Copyright © 2019-present anran758 5 | --- 6 | 7 |

8 | 9 | GitHub stars 10 | 11 | 12 | GitHub forks 13 | 14 | 15 | CRAN/METACRAN 16 | 17 |

18 | 19 | > :books: 记录 Web 领域的研究与实践 20 | 21 | ## 导读 22 | 23 | **开发语言相关的笔记** 24 | 25 | - [HTML](./develop/html/README.md) 26 | - [CSS 实践笔记](./develop/css/README.md) 27 | - [CSS 理论笔记](./develop/css/theory.md) 28 | - [JavaScript](./develop/javascript/README.md) 29 | - [TypeScript](./develop/javascript/typescript.md) 30 | - [React](./develop/javascript/react.md) 31 | - [Vuejs](./develop/javascript/vue.md) 32 | - [RegExp (正则表达式)](./REGEXP) 33 | 34 | **项目管理** 35 | 36 | - [Git 使用指南](./git) 37 | - [Hg 使用指南](./hg) 38 | - [Jira 项目管理](./jira) 39 | 40 | **解决方案** 41 | 42 | - [Mobile 开发](./develop/mobile/README.md) 43 | - [DevOps](./operations/README.md) 44 | 45 | **其他** 46 | 47 | - [前端技术要点](./topic/README.md) 48 | - [扩展阅读](./further) 49 | - [术语表](./further/glossary.md) 50 | - [web 书单](./further/booklist.md) 51 | - [职场常用英语](./further/en.md) 52 | - [实用的在线工具](./further/booklist.md) 53 | 54 | ## 专栏与博客 55 | 56 | - [anran758's blog](https://anran758.github.io/blog/): 分享 web 相关的教程、科普实用/常用的工具库、实际业务场景分析与解决方案、计算机相关的笔记等。 57 | - [专栏 | 初级前端工程师的进阶之路](https://zhuanlan.zhihu.com/c_1147180666474176512): 专门针对初级工程师进阶时常遇到的一些问题专辑。 58 | 59 | ## 推荐阅读 60 | 61 | - [Introducing npx: an npm package runner | npx 简介](https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b) 62 | - [usehooks | React Hooks 封装示例](https://usehooks.com/) 63 | - [The Missing Semester of Your CS Education (中译版) | 计算机教育中缺失的一课 | MIT](https://missing-semester-cn.github.io/) 64 | -------------------------------------------------------------------------------- /docs/REGEXP/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebarDepth: 3 3 | --- 4 | 5 | 6 | 7 | # REGEXP (正则表达式) 8 | 9 | ![banner](./images/regex.jpg) 10 | 11 | > tips: 善用`Ctrl + F`输入关键字能提高查询的效率哟~ 12 | 13 | 自己收集了一套针对工作中所需的正则表达式. 多适用于字符串处理、表单验证、日志数据分析等场合,实用高效, 将长期维护。 14 | 15 | - [常见正则校验](#常见正则校验) 16 | - [表单验证](#表单验证) 17 | - [网络相关](#网络相关) 18 | - [联系方式](#联系方式) 19 | - [匹配特定数字](#匹配特定数字) 20 | - [字符串相关](#字符串相关) 21 | - [匹配语系字符范围](#匹配语系字符范围) 22 | - [正则函数使用示例](#正则函数使用示例) 23 | - [replace](#replace) 24 | - [test](#test) 25 | - [正则技巧](#正则技巧) 26 | - [反向引用](#反向引用) 27 | - [忽略分組](#忽略分組) 28 | - [前瞻](#前瞻) 29 | 30 | --- 31 | 32 | **[REGEXP 可视化工具](https://regexper.com/)** 33 | 34 | 39 | 40 | ## 常见正则校验 41 | 42 | ### 表单验证 43 | 44 | ```javascript 45 | // 用户名正则,4到16位(字母,数字,下划线,减号) 46 | var userNameReg = /^[a-zA-Z0-9_-]{4,16}$/; 47 | 48 | // 必须拥有数字和特殊字符,并且在6 ~ 16位之间 49 | // (?=.*[0-9]) - 断言一个字符串至少有一个数字; 50 | // (?=.*[!@#$%^&*]) - 断言一个字符串至少有一个特殊字符。 51 | var reg = /^(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{6,16}$/; 52 | 53 | // 匹配邮箱地址 54 | var mailReg = /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/; 55 | 56 | // 中国六位数的邮政编码 57 | var postalCode = /^\d{6}$/; 58 | 59 | // 匹配15~18位身份证 60 | var IDCard = 61 | /(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}$)/; 62 | 63 | // 匹配18位的新版身份证 64 | var IDCard_18 = 65 | /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/; 66 | 67 | // 校验输入框是字符数为是否为 4~16 位(英文长度为1, 汉字长度为2) 68 | var numName = /^[a-zA-Z0-9]{4,16}$/; 69 | var mate = numName.test(value.replace(/[\u4e00-\u9fa5]/g, "aa")); 70 | ``` 71 | 72 | ### 网络相关 73 | 74 | ```js 75 | //ipv4地址正则 76 | var IPReg = 77 | /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; 78 | 79 | // Reg Hex颜色正则 80 | var pattern = /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/; 81 | 82 | // URL正则 83 | var urlReg = 84 | /^((https?|ftp|file):\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/; 85 | 86 | // 匹配JSON格式 87 | var reg = /^\w+\(({[^()]+})\)$/; 88 | ``` 89 | 90 | 匹配`json`字符串 91 | 92 | ```js 93 | var ret = response.data; 94 | if (typeof ret === "string") { 95 | var reg = /^\w+\(({[^()]+})\)$/; 96 | var matches = ret.match(reg); 97 | 98 | if (matches) ret = JSON.parse(matches[1]); 99 | } 100 | 101 | res.json(ret); 102 | ``` 103 | 104 | ### 联系方式 105 | 106 | ```js 107 | // 5-11位的腾讯qq号 108 | var qqReg = /^[1-9][0-9]{4,11}$/; 109 | 110 | // 微信号正则,6至20位,以字母开头,字母,数字,减号,下划线 111 | var qqReg = /^[a-zA-Z]([-_a-zA-Z0-9]{5,19})+$/; 112 | 113 | // 国内常见 114 | var phone = /^1[3|5|8|9]\d{9}$/; 115 | 116 | // 固定电话 117 | var telephone = /^(0[0-9]{2})\d{8}$|^(0[0-9]{3}(\d{7,8}))$/; 118 | ``` 119 | 120 | ### 匹配特定数字 121 | 122 | ```javascript 123 | // 匹配正整数 124 | var reg = /^[1-9]\d*$/; 125 | 126 | // 匹配负整数 127 | var reg = /^-[1-9]\d*$/; 128 | 129 | // 匹配整数 130 | var reg = /^-?[1-9]\d*$/; 131 | 132 | // 匹配非负整数(正整数 + 0) 133 | var reg = /^[1-9]\d*|0$/; 134 | 135 | // 匹配非正整数(负整数 + 0) 136 | var reg = /^-[1-9]\d*|0$/; 137 | 138 | // 匹配正浮点数 139 | var reg = /^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$/; 140 | 141 | // 匹配负浮点数 142 | var reg = /^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$/; 143 | 144 | // 匹配浮点数 145 | var reg = /^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$/; 146 | 147 | // 匹配非负浮点数(正浮点数 + 0) 148 | var reg = /^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$/; 149 | 150 | // 匹配非正浮点数(负浮点数 + 0) 151 | var reg = /^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$/; 152 | ``` 153 | 154 | ### 字符串相关 155 | 156 | ```javascript 157 | // 匹配由26个英文字母组成的字符串 158 | var reg = /^[A-Za-z]+$/; 159 | 160 | // 匹配由26个英文字母的大写组成的字符串 161 | var reg = /^[A-Z]+$/; 162 | 163 | // 匹配由26个英文字母的小写组成的字符串 164 | var reg = /^[a-z]+$/; 165 | 166 | // 匹配由数字和26个英文字母组成的字符串 167 | var reg = /^[A-Za-z0-9]+$/; 168 | 169 | // 匹配由数字、26个英文字母或者下;划线组成的字符串 170 | var reg = /^\w+$/; 171 | 172 | // 匹配空白行的正则表达式 173 | var reg = /\n\s*\r/; 174 | 175 | // 匹配首尾空白字符的正则表达式 176 | var reg = /^\s*|\s*$/; 177 | var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; 178 | 179 | // 匹配双字节字符(包括汉字在内, 一个双字节字符长度计2,ASCII字符计1) 180 | var reg = /[^\x00-\xff]/g; 181 | ``` 182 | 183 | --- 184 | 185 | ### 匹配语系字符范围 186 | 187 | 用法:`/^[\u4E00-\u9FA5]+$/`(匹配简体中文) 188 | 189 | `2E80~33FFh`:中日韩符号区。收容康熙字典部首、中日韩辅助部首、注音符号、日本假名、韩文音符,中日韩的符号、标点、带圈或带括符文数字、月份,以及日本的假名组合、单位、年号、月份、日期、时间等。 190 | 191 | `3400~4DFFh`:中日韩认同表意文字扩充A区,总计收容6,582个中日韩汉字。 192 | 193 | `4E00~9FFFh`:中日韩认同表意文字区,总计收容20,902个中日韩汉字。 194 | 195 | `A000~A4FFh`:彝族文字区,收容中国南方彝族文字和字根。 196 | 197 | `AC00~D7FFh`:韩文拼音组合字区,收容以韩文音符拼成的文字。 198 | 199 | `F900~FAFFh`:中日韩兼容表意文字区,总计收容302个中日韩汉字。 200 | 201 | `FB00~FFFDh`:文字表现形式区,收容组合拉丁文字、希伯来文、阿拉伯文、中日韩直式标点、小符号、半角符号、全角符号等。 202 | 203 | ## 正则函数使用示例 204 | 205 | ### replace 206 | 207 | ```javascript 208 | // 使用正则匹配中文字节, 将其替换为xx, 再获取字符串的长度就是完整的长度了. 209 | function getLen(str) { 210 | return str.replace(/[^\x00-\xff]/g, "xx").length; 211 | } 212 | ``` 213 | 214 | ### test 215 | 216 | ```javascript 217 | // 匹配是否符合邮件规则 218 | var reg = /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/; 219 | 220 | // test返回一个布尔值, 表示是否匹配到制定字符串 221 | var mail = reg.test("anran758@gmail.com"); 222 | 223 | if (mail) { 224 | // 如果邮件格式正确的话, 就可以做点啥了(雾 225 | } 226 | ``` 227 | 228 | ## 正则技巧 229 | 230 | ### 反向引用 231 | 232 | ```javascript 233 | // 比如这里我们想让这个日期格式反转 234 | // 正则括号是一个分组, 下面的代码就捕获了三个分组 235 | // 通过$分组符来转换位置, 来达到我们想要的结果 236 | "2018-3-21".replace(/(\d{4})-(\d{1,2})-(\d{1,2})/g, "$2/$3/$1"); // "3/21/2018" 237 | ``` 238 | 239 | ### 忽略分組 240 | 241 | 不希望捕获某些分组, 只需要分组内加上`?:`即可: 242 | 243 | ```javascript 244 | var reg = /(?:Byron).(ok)/; 245 | "Byron-ok".replace(reg, "$1"); // 只匹配了 ok 246 | ``` 247 | 248 | ### 前瞻 249 | 250 | | 名字 | 正則 | 251 | | -------- | ------------- | 252 | | 正向前瞻 | exp(?=assert) | 253 | | 负向前瞻 | exp(?!assert) | 254 | 255 | 正向前瞻就是匹配前者, 效验后者是否存在. 256 | 257 | ```javascript 258 | // 这个正则的意思是: 匹配一个单词字符( [a-zA-Z0-9_] ), 然后验证后面是不是数字 259 | // 结果为: "X2*3". 因为3后面没有数字, 所以没有匹配到. 260 | "a2*3".replace(/\w(?=\d)/g, "X"); 261 | 262 | // 结果为: "X2*X4X8" 263 | // 总的说就是 264 | "a2*34v8".replace(/\w(?=\d)/g, "X"); 265 | ``` 266 | 267 | 负向前瞻则相反, 匹配前面, 替代后面 268 | 269 | ```javascript 270 | // a 是单词字符, 后面是数字, 因此没有匹配到 271 | // 2 是单词字符, 后面不是数字, 被替换成X 272 | // * 不是单词字符 因此没有匹配到 273 | // 3 是单词字符, 后面是数字, 因此没有匹配到 274 | // 4 是单词字符, 后面不是数字, 被替换成X 275 | // v 是单词字符, 后面是数字, 因此没有匹配到 276 | // 8 是单词字符, 后面没有匹配到数字, 被替换成X 277 | // 结果: aX*4XvX 278 | "a2*34v8".replace(/\w(?!\d)/g, "X"); 279 | ``` 280 | 281 | --- 282 | 283 | 可视化正则表达式, 可以试试[regexper](https://regexper.com/), 让你看懂正则匹配的走向. 284 | 285 | ![regexper](./images/regexper.png) 286 | 287 | 如果有上述正则规则存在问题, 可在 issue 留言探讨~ 288 | -------------------------------------------------------------------------------- /docs/REGEXP/images/regex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/REGEXP/images/regex.jpg -------------------------------------------------------------------------------- /docs/REGEXP/images/regexper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/REGEXP/images/regexper.png -------------------------------------------------------------------------------- /docs/_images/box-model-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/_images/box-model-example.png -------------------------------------------------------------------------------- /docs/_images/css-grayscale-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/_images/css-grayscale-example.png -------------------------------------------------------------------------------- /docs/_images/event_loop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/_images/event_loop.gif -------------------------------------------------------------------------------- /docs/_images/git-merge-difference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/_images/git-merge-difference.png -------------------------------------------------------------------------------- /docs/_images/koa-middleware.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/_images/koa-middleware.png -------------------------------------------------------------------------------- /docs/_images/libuv.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/_images/libuv.jpeg -------------------------------------------------------------------------------- /docs/_images/youtube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/_images/youtube.png -------------------------------------------------------------------------------- /docs/_images/z-index-stacking-level.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/_images/z-index-stacking-level.png -------------------------------------------------------------------------------- /docs/dev-ops.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # DevOps 4 | 5 | - [版本管理与编辑器](#版本管理与编辑器) 6 | - [vim](#vim) 7 | - [iTerm2](#iterm2) 8 | - [命令行工具](#命令行工具) 9 | - [macos](#macos) 10 | - [windows](#windows) 11 | - [环境配置](#环境配置) 12 | - [淘宝镜像](#淘宝镜像) 13 | - [更新 Node.js 版本](#更新-nodejs-版本) 14 | - [更新 package.json 中的版本号](#更新-packagejson-中的版本号) 15 | - [常用快捷键速览](#常用快捷键速览) 16 | - [windows 速查快捷键](#windows-速查快捷键) 17 | - [MacOS 常用快捷键](#macos-常用快捷键) 18 | - [nginx](#nginx) 19 | - [基础配置](#基础配置) 20 | - [启用 HTTPS 的配置](#启用-https-的配置) 21 | - [反向代理配置](#反向代理配置) 22 | - [启用 Gzip 压缩](#启用-gzip-压缩) 23 | - [配置 CORS](#配置-cors) 24 | - [常见错误](#常见错误) 25 | - [npm 发布失败](#npm-发布失败) 26 | - [npm 安装依赖报权限不足的问题](#npm-安装依赖报权限不足的问题) 27 | 28 | ## 版本管理与编辑器 29 | 30 | ### vim 31 | 32 | **Tips** 33 | 34 | 1. 输入 `vim` 命令前需要将输入法设为英文, 否则可能会遇到输入不了命令的问题. 35 | 2. 默认情况下 `vim` 属于普通模式,按下 `:` 进入命令行模式,以下命令并不是都用于命令行模式的命令。如普通模式输入 `gg` 可以将光标跳到文件首行,但在命令行模式输入是不起效的,必须退出命令行模式才可以使用。 36 | 3. 输入 `Esc` 恢复为普通模式。 37 | 38 | **退出 vim:** 39 | 40 | | 命令 | 说明 | 41 | | --------- | ---------------------------------------- | 42 | | `:q` | 不保存文件,退出vi. | 43 | | `:q!` | 不保存文件,强制退出vi. | 44 | | `:w` | 保存文件但不退出 `vim` | 45 | | `:wq` | 保存文件并退出 `vim` | 46 | | `:wq!` | 强制保存文件,并退出 `vim` | 47 | | `:w!` | 强制保存,不推出 `vim` | 48 | | `:w file` | 将修改另外保存到 `file` 中,不退出 `vim` | 49 | | `:e!` | 放弃所有修改,从上次保存文件开始再编辑 | 50 | 51 | **光标调整:** 52 | 53 | | 命令 | 说明 | 54 | | ---------------------- | ------------------------------ | 55 | | `0`、`^` | 跳到行首 | 56 | | `$` | 跳到行尾 | 57 | | `:` | 直接输入数字可以跳去指定的行号 | 58 | | `gg`、`:1` | 跳到文件第一行行首 | 59 | | `G`、`:$`、`Shift + G` | 跳到文件最后一行行首 | 60 | | `/{搜索的文本}` | 搜索内容 | 61 | | `n` | 搜索内容向前找 | 62 | | `N` | 搜索内容向后找 | 63 | 64 | **文本处理:** 65 | 66 | | 命令 | 说明 | 67 | | ----------------- | ---------------------------------------------- | 68 | | `dd` | 删除当前行 | 69 | | `:[start],[end]d` | 删除指定行,例如 `:3,5d` 是删除第 3~5 行的文本 | 70 | 71 | ### iTerm2 72 | 73 | iTerm 2是 Terminal 的替代品,是 iTerm 的后继产品。它有好看的 UI 界面与使用的功能,比如[分隔终端](https://www.iterm2.com/features.html)等功能。 74 | 75 | **常用快捷键** 76 | 77 | | 快捷键 | 说明 | 78 | | --------------- | ------------ | 79 | | `Command` + `F` | 查找内容 | 80 | | `Ctrl` + `P` | 上一条命令 | 81 | | `Ctrl` + `R` | 搜索命令历史 | 82 | 83 | **输入** 84 | 85 | | 快捷键 | 说明 | 86 | | --------------- | ---------------------------------- | 87 | | `Command` + `R` | 将输出过的信息隐藏到屏幕外(伪清屏) | 88 | | `Ctrl` + `L` | 清屏 | 89 | | `Ctrl` + `U` | 清除当前行 | 90 | | `Ctrl` + `A` | 跳到行首 | 91 | | `Ctrl` + `E` | 跳到行尾 | 92 | | `Ctrl` + `D` | 删除当前光标的字符 | 93 | | `Ctrl` + `H` | 删除光标之前的字符 | 94 | | `Ctrl` + `W` | 删除光标之前的单词 | 95 | | `Ctrl` + `K` | 删除到文本末尾 | 96 | | `Ctrl` + `T` | 交换光标处文本 | 97 | 98 | **标签页** 99 | 100 | | 快捷键 | 说明 | 101 | | ---------------------------------------------- | ------------------------ | 102 | | `Command` + `` | 调到第 `` 个 Tab | 103 | | `Command` + `T` | 新建标签 | 104 | | `Command` + `W` | 关闭标签 | 105 | | `Command` + `number`、`Command` + `left/right` | 切换标签 | 106 | 107 | **分屏** 108 | 109 | | 快捷键 | 说明 | 110 | | ----------------------------------------------------------------- | -------------- | 111 | | `Command` + `D` | 垂直分屏 | 112 | | `Command` + `Shift` + `D` | 水平分屏 | 113 | | `Command` + `Option` + `方向键`、`Command` + `[`、`Command` + `]` | 切换屏幕 | 114 | | `Command` + `;` | 查看历史命令 | 115 | | `Command` + `Shift` + `H` | 查看剪贴板历史 | 116 | | `Command` + `Enter` | 切换全屏 | 117 | 118 | **其他** 119 | 120 | - [iterm 配置utf8编码,本地终端中文不乱码,ssh 远程中文乱码](https://segmentfault.com/q/1010000002426378) 121 | 122 | ## 命令行工具 123 | 124 | 命令行工具是开发人员日常工作中不可或缺的部分,了解如何高效使用命令行可以显著提高工作效率。 125 | 126 | **通用命令** 127 | 128 | 在Windows和MacOS平台上,有许多命令是通用的,以下列出了一些基础且常用的命令: 129 | 130 | | command | 说明 | 131 | | -------------------------------- | ------------------------------ | 132 | | `pwd` | 显示当前路径 | 133 | | `mv ` | 移动文件 | 134 | | `mv ` | 重命名文件 | 135 | | `netstat –ano` | 查看所有进程端口和进程 ID | 136 | | `netstat –ano \| findstr 8080` | 查看所有 8080 端口 | 137 | | `dir`、`ls` | 查看当前目录下的文件 | 138 | | `type NUL > .nojekyll` | 新建文件, 并命名为 `.nojekyll` | 139 | 140 | ### macos 141 | 142 | | command | 说明 | 143 | | ------------------------ | -------------------------------------- | 144 | | `pbcopy` | 操作粘贴板 | 145 | | `pwd \| pbcopy` | 复制当前路径到粘贴板 | 146 | | `pbcopy < blog-post.txt` | 将文件 blog-post.text 的内容读入粘贴板 | 147 | 148 | **操作粘贴板** 149 | 150 | 将当前目录的路径复制到剪贴板: 151 | 152 | ```bash 153 | # `|` 是管道符,即前一个命令的输出结果会作为后一个命令接收的输入 154 | pwd | pbcopy 155 | ``` 156 | 157 | 将当前目录下的 `file.txt` 文件的内容复制到剪贴板中: 158 | 159 | ```bash 160 | pbcopy < file.txt 161 | ``` 162 | 163 | **批量修改文件名** 164 | 165 | 可以通过 Homebrew 安装 `rename` 可以实现批量修改文件名称。 166 | 167 | ```bash 168 | brew install rename 169 | 170 | # 替换文件 171 | rename 's/from/to/' *.txt 172 | ``` 173 | 174 | 假如某目录有以下文件: 175 | 176 | - `report1_2023.txt` 177 | - `report2_2023.txt` 178 | - `summary_2023.txt` 179 | 180 | 现在,我们想将这些文件中的年份从 `2023` 改为 `2024`,可以执行以下命令: 181 | 182 | ```bash 183 | rename 's/_2023/_2024/' *.txt 184 | ``` 185 | 186 | 解释: 187 | 188 | - `s/_2023/_2024/`:这是一个 Perl 正则表达式,表示将匹配到的字符串 `_2023` 替换为 `_2024`。 189 | - `s` 表示替换(substitute)操作。 190 | - `/` 是分隔符,用来区分不同部分的正则表达式。 191 | - `_2023` 是需要被替换的文本。 192 | - `_2024` 是替换后的文本。 193 | - `*.txt`:这指定了要操作的文件,`*`是一个通配符,表示匹配当前目录下所有以`.txt`结尾的文件。 194 | 195 | **整理文本** 196 | 197 | 假设有一个服务器的访问日志文件 `access.log`,其中每行记录包含了访问时间、IP 地址、请求类型、URL、返回状态码等信息,格式如下: 198 | 199 | ```log 200 | 127.0.0.1 - - [10/Oct/2023:13:55:36 +0200] "GET /index.html HTTP/1.1" 200 532 "-" 201 | "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" 202 | 192.168.1.1 - - [10/Oct/2023:13:55:37 +0200] "POST /submit-form HTTP/1.1" 404 152 "-" 203 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" 204 | ... 205 | ``` 206 | 207 | 现在想要分析这些日志,提取每个 IP 地址的访问次数: 208 | 209 | ```bash 210 | awk '{print $1}' access.log | sort | uniq -c | sort -nr 211 | ``` 212 | 213 | > awk 的字段区分默认是按照空格或制表符作为分隔符,$1 指的是第一个字段 214 | 215 | - `awk '{print $1}' access.log`:使用 `awk` 打印每行的第一个字段(IP 地址)。 216 | - `sort`:对输出的 IP 地址进行排序,以便 `uniq` 命令可以正确统计。 217 | - `uniq -c`:统计每个唯一 IP 地址的出现次数。 218 | - `sort -nr`:对结果按照访问次数进行降序排序。 219 | 220 | **"列出当前目录下的从大到小排序的文件名和大小"** 221 | 222 | 有时候在做构建优化的相关工作时,需要比较优化前与优化后的成果。因此需要将某构建目录下的文件信息记录下来,以方便比对: 223 | 224 | ```bash 225 | ls -lhS | awk 'NR > 1 {printf("| %-5s | %-46s |\n", $5, $9);}' 226 | ``` 227 | 228 | 此命令使用 `ls` 和 `awk` 工具来筛选并格式化当前目录下的文件信息,便于进行构建优化前后的比对。 229 | 230 | `ls` 是列出目录内容的命令: 231 | 232 | - `-l` 选项表示以长格式列出信息,显示文件的详细信息,如权限、所有者、大小等。 233 | - `-h` 选项使得文件大小以易读的格式显示(如 KB、MB)。 234 | - `-S` 选项按文件大小排序,显示结果以文件大小降序排列。 235 | 236 | `awk` 命令用于文本处理,这里用于格式化 `ls` 命令的输出: 237 | 238 | - `NR > 1`:这是一个条件判断,`NR` 是 `awk` 的内置变量,代表"当前记录号",或者可以理解为"当前是第几行"。`NR > 1` 的意思是对除了第一行之外的每一行执行大括号 `{}` 里的命令。这通常用来跳过标题行或是特定的不需要处理的第一行数据。 239 | - `printf("| %-5s | %-46s |\n", $5, $9);`:是 `awk` 的 `printf` 函数调用,用于格式化输出数据。 240 | - `| %-5s |`:表示以竖线开始,然后输出第五个字段(`$5`),这里指的是文件大小。`%-5s` 表示该字段为字符串格式,左对齐,并保证至少有5个字符的宽度,如果不足5个字符,则用空格填充到5个字符宽。这样做可以确保输出的对齐美观。 241 | - `%-46s |`:表示输出第九个字段(`$9`),即文件名。同样,`%-46s` 表示该字段为字符串格式,左对齐,并保证至少有46个字符的宽度,不足部分用空格填充。这保证了即使文件名长度不一,输出也能整齐对齐。 242 | - `\n`:表示每条记录后输出一个换行符,即每条输出占用一行。 243 | 244 | 每行输出的结果为: 245 | 246 | ```log 247 | | 文件大小 | 文件名 | 248 | ``` 249 | 250 | ### windows 251 | 252 | | 命令 | 说明 | 253 | | ------------ | ---------------------------- | 254 | | `explorer` | 打开文件管理器 | 255 | | `explorer .` | 打开**当前路径**的文件管理器 | 256 | 257 | ## 环境配置 258 | 259 | ### 淘宝镜像 260 | 261 | `npm` 和 `yarn` 都可以通过国内的淘宝镜像来安装依赖。 262 | 263 | 如果只想单个项目中使用淘宝镜像来安装依赖,可以输入以下命令: 264 | 265 | ```shell 266 | # npm 267 | npm install --registry=https://registry.npm.taobao.org 268 | 269 | # yarn 270 | yarn --registry=https://registry.npm.taobao.org 271 | ``` 272 | 273 | 也可以安装他们定制的 `cnpm` 命令: 274 | 275 | ```shell 276 | # 全局安装命令 277 | npm install -g cnpm --registry=https://registry.npm.taobao.org 278 | 279 | # 使用 cnpm 安装依赖 280 | cnpm install 281 | ``` 282 | 283 | ### 更新 Node.js 版本 284 | 285 | 推荐使用 `nvm` 来管理 `Node.js` 的版本: 286 | 287 | - Windows: [Node Version Manager (nvm) for Windows](https://github.com/coreybutler/nvm-windows#node-version-manager-nvm-for-windows) 288 | - MacOS/unix: [Installing and Updating](https://github.com/nvm-sh/nvm#installing-and-updating) 289 | 290 | 使用方法如下: 291 | 292 | ```shell 293 | # [mac]: 查看可以安装的 Node.js 版本 294 | nvm ls-remote 295 | 296 | # [windows]: 查看本地已安装的版本 297 | # 加上 available 参数后查看 Node.js 可安装的版本 298 | nvm list [available] 299 | 300 | # 查看本地已安装的版本 301 | vm ls 302 | 303 | # 安装指定版本 304 | nvm install 6.14.4 305 | 306 | # 安装最新版本的 Node.js 307 | nvm install --lts 308 | 309 | # 使用已安装的版本 310 | nvm use 6.14.4 311 | ``` 312 | 313 | 注意:在 mac 环境中,某些编辑器的插件会使用 bash 来执行 node 命令,哪怕最常用的是 `zsh`。因此即便你装了 `nvm` 并且能在 `zsh` 使用,但 `bash` 默认配置未设置的情况可能会抛出 `nvm not found` 的错误。 314 | 因此你可以尝试执行以下命令来修复路径的问题。 315 | 316 | ```bash 317 | source ~/.nvm/nvm.sh 318 | ``` 319 | 320 | 从 `nvm ls` 可以看到当前安装的 node 版本,其中有个关键词是 `system`。`system` 是系统安装的版本,因此 `nvm` 不能直接删除或更新它。因此可以通过 `n` 包来更新: 321 | 322 | ```bash 323 | npx n latest 324 | ``` 325 | 326 | ### 更新 package.json 中的版本号 327 | 328 | 使用 `npm-check-updates` 工具进行版本升级: 329 | 330 | ```shell 331 | # 全局安装 332 | npm -g npm-check-updates 333 | num -u 334 | ``` 335 | 336 | 第三方库 `lerna` 中有个 `lerna version` 也能根据当前的版本引导开发者选择本次升级的版本。 337 | 338 | ## 常用快捷键速览 339 | 340 | 快捷键是提高工作效率的重要手段。以下列出了在Windows和MacOS操作系统上常用的快捷键。 341 | 342 | - [Mac 键盘快捷键](https://support.apple.com/zh-cn/HT201236) 343 | - [Windows 键盘快捷键](https://support.microsoft.com/zh-cn/help/12445/windows-keyboard-shortcuts) 344 | - [Chrome 键盘快捷键](https://support.google.com/chrome/answer/157179?hl=zh-Hans) 345 | - [VS Code Tips and Tricks](https://github.com/Microsoft/vscode-tips-and-tricks) 346 | 347 | ### windows 速查快捷键 348 | 349 | - `win` + `Tab`: 创建新的虚拟桌面 350 | - `win` + `Ctrl` + `D`: 创建新的虚拟桌面 351 | - `win` + `Ctrl` + `F4`: 删除当前虚拟桌面 352 | - `win` + `Ctrl` + `left/right`: 切换虚拟桌面 353 | - `win` + `E`: 打开资源管理器 354 | 355 | ### MacOS 常用快捷键 356 | 357 | | 快捷键 | 说明 | 358 | | ------------------------- | ------------------ | 359 | | `Shift` `+` `Alt` `+` `.` | 显示和隐藏隐藏文件 | 360 | 361 | ## nginx 362 | 363 | 修改完配置后在命令行输入 `nginx -s reload` 平滑使用 nginx 配置。reload 后会启动新的进程接受新请求,对于未处理完的请求还是用旧的配置,直到所有请求处理完毕后,旧的进程进行会退出。 364 | 365 | ### 基础配置 366 | 367 | ```nginx 368 | server { 369 | listen 80; # HTTP的默认端口 370 | server_name react-app.com; # 你的域名 371 | 372 | root /var/www/react-app; # 指向你的前端项目构建产物目录 373 | index index.html; # 默认文档 374 | 375 | location / { 376 | try_files $uri $uri/ /index.html; # 用于支持 SPA 的前端路由 377 | } 378 | } 379 | ``` 380 | 381 | 这个配置告诉 Nginx 监听80端口,为 `example.com` 域名服务,并将所有 HTTP 请求定向到项目的根目录。`try_files` 指令用于处理SPA的前端路由,当直接访问一个不存在的路径时,Nginx 会返回 `index.html` 页面,由前端路由器处理请求路径。 382 | 383 | ### 启用 HTTPS 的配置 384 | 385 | 若已获取SSL证书及私钥,并存放于 `/etc/nginx/ssl` 目录,以下配置示例启用HTTPS支持: 386 | 387 | ```nginx 388 | # 注意, nginx 可以定义多个 server 块。因此上面 80 端口的配置和现在这个 443 端口的配置是可以共存的,不需要覆盖。 389 | server { 390 | listen 443 ssl; # HTTPS 的默认端口 391 | server_name react-app.com; 392 | 393 | ssl_certificate /etc/nginx/ssl/react-app.com.pem; # SSL证书路径 394 | ssl_certificate_key /etc/nginx/ssl/react-app.com.key; # 私钥路径 395 | 396 | root /var/www/react-app; 397 | index index.html; 398 | 399 | location / { 400 | try_files $uri $uri/ /index.html; 401 | } 402 | } 403 | ``` 404 | 405 | ### 反向代理配置 406 | 407 | 对于前端应用中的 API 请求,通常需要通过 Nginx 将这些请求转发到后端服务。以下配置示例展示了如何将以`/api` 开头的请求转发到后端服务: 408 | 409 | ```nginx 410 | location /api { 411 | proxy_pass http://backend-server.com; # 后端服务器地址 412 | proxy_http_version 1.1; 413 | proxy_set_header Upgrade $http_upgrade; 414 | proxy_set_header Connection 'upgrade'; 415 | proxy_set_header Host $host; 416 | proxy_cache_bypass $http_upgrade; 417 | } 418 | ``` 419 | 420 | ### 启用 Gzip 压缩 421 | 422 | 为了提高网页加载速度,可以在Nginx配置中启用Gzip压缩。以下配置启用了对特定类型文件的压缩: 423 | 424 | ```nginx 425 | gzip on; 426 | gzip_disable "msie6"; 427 | gzip_vary on; 428 | gzip_proxied any; 429 | gzip_comp_level 6; 430 | gzip_buffers 16 8k; 431 | gzip_http_version 1.1; 432 | gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; 433 | ``` 434 | 435 | 这些指令配置了Gzip压缩的各种参数,如压缩级别(`gzip_comp_level`)、压缩缓冲区大小(`gzip_buffers`),以及需要压缩的MIME类型(`gzip_types`)。 436 | 437 | ### 配置 CORS 438 | 439 | 为了允许跨域请求,可以在Nginx中配置CORS。以下配置为所有响应添加了CORS相关的头部,允许来自任何源的请求: 440 | 441 | ```nginx 442 | location / { 443 | if ($request_method = 'OPTIONS') { 444 | add_header 'Access-Control-Allow-Origin' '*'; 445 | add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; 446 | add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; 447 | add_header 'Access-Control-Max-Age' 1728000; 448 | add_header 'Content-Type' 'text/plain; charset=utf-8'; 449 | add_header 'Content-Length' 0; 450 | return 204; 451 | } 452 | add_header 'Access-Control-Allow-Origin' '*'; 453 | add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; 454 | add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; 455 | } 456 | ``` 457 | 458 | 此配置对预检请求(OPTIONS请求)和实际请求都添加了CORS头部,允许跨域资源共享。 459 | 460 | ## 常见错误 461 | 462 | 开发或运维时常常遇到的问题。 463 | 464 | ### npm 发布失败 465 | 466 | ```bash 467 | ➜ module-test git:(master) npm publish 468 | npm ERR! publish Failed PUT 403 469 | npm ERR! code E403 470 | npm ERR! [no_perms] Private mode enable, only admin can publish this module [no_perms] Private mode enable, only admin can publish this mod 471 | ule: module-test 472 | **** 473 | ``` 474 | 475 | 没有权限的原因可能是我们按照了淘宝的`npm`镜像,发布通过镜像代理,就会有权限问题。这时候将权限调整回来即可: 476 | 477 | ```bash 478 | ➜ module-test git:(master) npm config set registry http://registry.npmjs.org 479 | 480 | ➜ module-test git:(master) npm publish 481 | npm ERR! code ENEEDAUTH 482 | npm ERR! need auth auth required for publishing 483 | npm ERR! need auth You need to authorize this machine using `npm adduser` 484 | 485 | npm ERR! A complete log of this run can be found in: 486 | npm ERR! /Users/anran/.npm/_logs/2019-04-27T13_56_25_234Z-debug.log 487 | 488 | # 添加账号 489 | ➜ module-test git:(master) npm adduser 490 | Username: anran758 491 | Password: 492 | Email: (this IS public) anran758@gmail.com 493 | Logged in as anran758 on http://registry.npmjs.org/. 494 | 495 | # 验证邮箱 496 | ➜ module-test git:(master) npm publish 497 | npm ERR! publish Failed PUT 403 498 | npm ERR! code E403 499 | npm ERR! you must verify your email before publishing a new package: https://www.npmjs.com/email-edit : module-test 500 | 501 | npm ERR! A complete log of this run can be found in: 502 | npm ERR! /Users/anran/.npm/_logs/2019-04-27T14_09_30_297Z-debug.log 503 | 504 | ➜ module-test git:(master) npm publish 505 | + module-test@1.0.0 506 | ``` 507 | 508 | ### npm 安装依赖报权限不足的问题 509 | 510 | 如果在安装依赖时发现错误中由以下错误, 可以尝试通过[此指南](https://github.com/sindresorhus/guides/blob/master/npm-global-without-sudo.md)解决问题: 511 | 512 | ```log 513 | Please try running this command again as root/Administrator. npm 514 | (node:10370) UnhandledPromiseRejectionWarning: Error: EACCES: permission denied, open '/Users/anran/.zshrc' 515 | ``` 516 | 517 | 如果是在项目内碰见权限问题,可以先检查是不是 `node_modules` 所属权限是 `root` 的,如是应该调整为当前用户才对(macOS 环境)。 518 | -------------------------------------------------------------------------------- /docs/develop/README.md: -------------------------------------------------------------------------------- 1 | # Web 开发 2 | 3 | 本篇幅主要记录 web 开发中遇到的实现技巧、问题与解决方案,侧重点在于解决问题。 4 | -------------------------------------------------------------------------------- /docs/develop/css/README.md: -------------------------------------------------------------------------------- 1 | # CSS 示例 2 | 3 | > css 实践搭配 codepen 预览效果会更佳噢~ 4 | 5 | **Table of Contents:** 6 | 7 | [[toc]] 8 | 9 | ## Layout 10 | 11 | ### 圣杯布局 12 | 13 | 圣杯布局实际上是讨论「三栏液态布局」的实现, 主要思想是让中间主要的内容先渲染, 两边相对来说没那么重要的放在后面加载. 14 | 15 | 圣杯布局让`container`上构建三个模块, 分别为`left`、`main`、`right`,其中`main`独占一行. 16 | 实现的原理如下: 17 | 18 | 1. 三者都使用 `float` 进行浮动. 19 | 2. `container` 使用 `padding` 为两侧栏腾出空位. 20 | 3. 将主要内容 `main` 排在前头, 让**DOM 树**先加载. 21 | 4. 两侧栏添加 `relative` 定位,左列使用 `margin-left: -100%`,右例使用 `margin-left: -右列宽度`。 22 | 23 | [示例](https://anran758.github.io/pages/demos/layout/grail) 24 | 25 | ![image](./design/images/auto-width.gif) 26 | 27 | ### 双飞翼布局 28 | 29 | 双飞翼布局和圣杯布局类似,也是左,中,右三列,中列里面会再套一个容器。 30 | 31 | - 中列宽度设置为`100%` 32 | - 使用负边距`margin-left`把左右两列拉到和中列同一行 33 | - 在中列内的容器 div 设置`margin-left`和`margin-right`给左右两列留下对应的空间 34 | 35 | 实现代码也很简单: 36 | 37 | ```html 38 | 39 |
40 | 41 |
42 |
中间弹性区
43 |
44 |
左边栏
45 |
右边栏
46 |
47 | 48 | 49 | 76 | ``` 77 | 78 | 圣杯布局和双飞翼布局解决的问题是一样的,都是两边定宽,中间自适应的三栏布局,中间栏要在放在文档流前面以优先渲染。 79 | 80 | 这样做主要是因为早年的网络和设备没有现在这么优秀,为了让主要的内容先向用户呈现,所以很多时候都使用这两种布局方式。甚至可以说,现在很多人都还在使用这两种布局方式。 81 | 82 | ### FlexBox 布局 83 | 84 | `FlexBox` 是 `CSS` 的一个新特性,这个新特性解决我们以前在 `CSS` 中很多麻烦问题,比如说内容的伸缩与扩展、垂直居中、等分列、等高列等等。 85 | 86 | `FlexBox` 顾名思义就是弹性盒子, 它可以规定弹性元素如何分配空间或者布局的方式. 下面就是个例子. 利用`flex`的计算的特性, 配合 js 的`onclick`实现出来的效果. 87 | ![flexBox-1](./design/images/flexbox-1.gif) 88 | 89 | 当我们将 Flex 布局运用在移动端, 更能体现出它的价值——它能适配移动端各种复杂的屏幕. qq 音乐的导航就是使用了`flex`的属性, 我们来随机测试一下机型. 能发现不管是什么尺寸屏幕下, `flex`都能合理的分配空间. 90 | 91 | ![flexBox-2](./design/images/flexbox-2.gif) 92 | 93 | 以下是 `Flex` 布局的参考资料: 94 | 95 | - [FlexBox 布局入门](https://zhuanlan.zhihu.com/p/106311718) 96 | - [FlexBox 布局实际用例](https://zhuanlan.zhihu.com/p/109144068) 97 | 98 | ### 响应式布局 99 | 100 | 响应式布局实际上是一个设计理念, 它是多项技术的综合体. 能适应于各种的屏幕. 其核心围绕着媒体查询(@media)。`max-width`是媒体查询的一个特性,其意思是指媒体类型小于或等于指定的宽度时, `min-width`则相反。在 [Bootstrap](https://getbootstrap.com/docs/4.1/layout/overview/) 中已经有相关文档的指导。 101 | 102 | 以下代码是当设备的宽度**大于等于**指定尺寸时,代码会被应用: 103 | 104 | ```css 105 | /* Small devices (landscape phones, devices width >= 576px) */ 106 | @media (min-width: 576px) { ... } 107 | 108 | /* Medium devices (tablets, devices width >= 768px) */ 109 | @media (min-width: 768px) { ... } 110 | 111 | /* Large devices (desktops, devices width >= 992px) */ 112 | @media (min-width: 992px) { ... } 113 | 114 | /* Extra large devices (large desktops, devices width >= 1200px) */ 115 | @media (min-width: 1200px) { ... } 116 | ``` 117 | 118 | 以下代码是当设备的宽度**小于**指定尺寸时,代码会被应用: 119 | 120 | ```css 121 | /* 超小型设备 (portrait phones, less than 576px) */ 122 | @media (max-width: 575.98px) { ... } 123 | 124 | /* 小型设备 (landscape phones, less than 768px) */ 125 | @media (max-width: 767.98px) { ... } 126 | 127 | /* 中型设备 (tablets, less than 992px) */ 128 | @media (max-width: 991.98px) { ... } 129 | 130 | /* 大型设备 (desktops, less than 1200px) */ 131 | @media (max-width: 1199.98px) { ... } 132 | 133 | /* 超大型设备 (large desktops, 1200px and up) */ 134 | @media (min-width: 1200px) { ... } 135 | ``` 136 | 137 | 以上使用 `.98px` 的原因在于避免 `max-width` 与 `min-width` 同时出现时规则用冲突的情况。具体原因参见: [Why does Bootstrap use a 0.02px difference between screen size thresholds in its media queries?](https://stackoverflow.com/questions/51566916/why-does-bootstrap-use-a-0-02px-difference-between-screen-size-thresholds-in-its) 138 | 139 | 还可以针对指定大小的设备宽度做定制化样式: 140 | 141 | ```css 142 | /* 超小型设备 (portrait phones, less than 576px) */ 143 | @media (max-width: 575.98px) { ... } 144 | 145 | /* 小型设备 (landscape phones, 576px and up) */ 146 | @media (min-width: 576px) and (max-width: 767.98px) { ... } 147 | 148 | /* 中型设备 (tablets, 768px and up) */ 149 | @media (min-width: 768px) and (max-width: 991.98px) { ... } 150 | 151 | /* 大型设备 (desktops, 992px and up) */ 152 | @media (min-width: 992px) and (max-width: 1199.98px) { ... } 153 | 154 | /* 超大型设备 (large desktops, 1200px and up) */ 155 | @media (min-width: 1200px) { ... } 156 | ``` 157 | 158 | 关于响应式布局设计的其他几个点可以看[这里](https://anran758.github.io/blog/2018/01/25/web-%E8%B5%B0%E8%BF%9Bweb%E7%A7%BB%E5%8A%A8%E5%BC%80%E5%8F%91/#%E5%93%8D%E5%BA%94%E5%BC%8F%E5%B8%83%E5%B1%80) 159 | 160 | ### Grid 161 | 162 | `Grid` 是新一代布局方式,下面是相关的学习资料: 163 | 164 | - [网格布局(Grid) | MDN](https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Grid_Layout) 165 | - [CSS Grid | freeCodeCamp](https://learn.freecodecamp.one/responsive-web-design/css-grid) 166 | 167 | ## Utils 168 | 169 | ### [display] 隐藏元素 170 | 171 | 如果项目用需要优化无障碍的体验,那应该避免使用`display: none`。因为辅助屏幕设备实际上是读不了设置了这个属性里的内容, 搜索引擎的爬虫蜘蛛也会过滤掉设置了`display: none` 里的内容. 172 | 173 | ```css 174 | .hidden { 175 | position: absolute; 176 | top: -9999em; 177 | } 178 | 179 | .hidden { 180 | position: absolute; 181 | clip: rect(1px 1px 1px 1px); /* IE6, IE7 */ 182 | clip: rect(1px, 1px, 1px, 1px); 183 | } 184 | ``` 185 | 186 | 如果不用顾忌无障碍的话, 也可以这个方法来避免页面回流 187 | 188 | ```css 189 | .hidden { 190 | position: absolute; 191 | visibility: hidden; 192 | } 193 | ``` 194 | 195 | ### [layout] 居中元素 196 | 197 | **常用的居中方法**: 198 | 199 | [单行垂直水平居中]: 容器 `height` 与 `line-height` 设为相同的值 200 | 201 | ```css 202 | .container { 203 | height: 30px; 204 | line-height: 30px; 205 | text-align: center; 206 | } 207 | ``` 208 | 209 | `absolute` + `margin` 分配剩余空间。这个方法**需要设置宽高**. 210 | 211 | ```css 212 | .container { 213 | width: 600px; 214 | height: 400px; 215 | position: absolute; 216 | left: 0; 217 | top: 0; 218 | right: 0; 219 | bottom: 0; 220 | margin: auto; 221 | } 222 | ``` 223 | 224 | `absolute` + `transform`自身宽高的一半, 副作用是`transform`会**占据原来的文档流位置**。 225 | 226 | ```css 227 | .container { 228 | position: absolute; 229 | top: 50%; 230 | left: 50%; 231 | transform: translate(-50%, -50%); 232 | } 233 | ``` 234 | 235 | 基于 `vertical-align` 的水平垂直居中 --by 张鑫旭 236 | 237 | ```html 238 |
239 |
240 |
内容占位
241 |
242 |
243 | ``` 244 | 245 | ```css 246 | .container { 247 | position: fixed; 248 | top: 0; 249 | right: 0; 250 | bottom: 0; 251 | left: 0; 252 | /* for IE8 */ 253 | /* background: url(data:image/png;base64,iVB...g==); */ 254 | /* for IE9+ */ 255 | background: rgba(0, 0, 0, 0.5); 256 | text-align: center; 257 | white-space: nowrap; 258 | z-index: 99; 259 | } 260 | .container:after { 261 | content: ""; 262 | display: inline-block; 263 | height: 100%; 264 | vertical-align: middle; 265 | } 266 | .dialog { 267 | display: inline-block; 268 | vertical-align: middle; 269 | border-radius: 6px; 270 | background-color: #fff; 271 | text-align: left; 272 | white-space: normal; 273 | } 274 | ``` 275 | 276 | `flex` 布局 277 | 278 | ```html 279 |
280 |
children
281 |
282 | ``` 283 | 284 | ```css 285 | .parent { 286 | display: flex; 287 | justify-content: center; 288 | align-items: center; 289 | width: 100px; 290 | height: 100px; 291 | border: 1px solid red; 292 | } 293 | ``` 294 | 295 | ### [text] 文本溢出隐藏 296 | 297 | **单行溢出:** 298 | 299 | `text-overflow` 只是用来说明文字溢出时用什么方式显示,要实现溢出时产生省略号的效果,还须配合其他属性. 300 | 301 | ```css 302 | /* 强制不断行, 单行超出范围出现省略号 */ 303 | .overflow { 304 | overflow: hidden; 305 | white-space: nowrap; 306 | text-overflow: ellipsis; 307 | } 308 | ``` 309 | 310 | **多行溢出:** 311 | 312 | ```css 313 | .line-clamp-2 { 314 | display: -webkit-box; 315 | -webkit-box-orient: vertical; 316 | -webkit-line-clamp: 2; 317 | line-clamp: 2; 318 | overflow: hidden; 319 | } 320 | ``` 321 | 322 | 若项目中有使用 `unoCSS`,则我们可以在 `uno.config.js` 中配置: 323 | 324 | ```js 325 | export default defineConfig({ 326 | // ... 327 | rules: [ 328 | [ 329 | /^line-clamp-(\d+)$/, 330 | ([, d], { constructCSS }) => 331 | constructCSS({ 332 | display: "-webkit-box", 333 | "-webkit-box-orient": "vertical", 334 | "-webkit-line-clamp": d, 335 | "line-clamp": d, 336 | overflow: "hidden", 337 | }), 338 | ], 339 | ], 340 | }); 341 | ``` 342 | 343 | 这样通过 `unoCSS` 的正则处理后可以直接在类名添加 `line-clamp-2` 等类名。 344 | 345 | ### [text] 文本颜色渐变 346 | 347 | ```css 348 | .text-gradient { 349 | background: linear-gradient(90deg, #00aeff, #3369e7); 350 | /* IE9+ */ 351 | -webkit-background-clip: text; 352 | -webkit-text-fill-color: transparent; 353 | -webkit-box-decoration-break: clone; 354 | box-decoration-break: clone; 355 | text-shadow: none; 356 | } 357 | ``` 358 | 359 | [点击此链接跳转至 codepen demo](https://codepen.io/anran758/pen/ExVRLeX) 360 | 361 | ## Feature 362 | 363 | ### [nav] 导航渐变色分割线 364 | 365 | 使用`after`对导航进行分割, 对`background`使用`linear-gradient`渐变. 366 | 367 | [点击此链接跳转至 codepen demo](https://codepen.io/anran758/pen/ypXYba) 368 | 369 | ![nav-split](./images/nav-split.png) 370 | 371 | ### [nav] 导航列表下标,悬浮动画显示 372 | 373 | 利用`:before`和`transition`实现悬浮后, 下标从底部中间向两边展开. 374 | 375 | [点击此链接跳转至 codepen demo](https://codepen.io/anran758/pen/BJZdLL) 376 | 377 | ![nav-anima](./images/nav-anima.png) 378 | 379 | ### [overflow] 查看更多 380 | 381 | 白色半透明遮罩的"查看更多",使用 `linear-gradient` 颜色渐变,再使用 `pointer-events: none` 清除默认事件. 382 | 383 | [点击此链接跳转至 codepen demo](https://codepen.io/anran758/pen/ppwwKN) 384 | 385 | ![background-more](./images/background-more.png) 386 | 387 | ### [animation] loading 388 | 389 | 我们可以利用 css3 属性来做一些动画 loading, 相对于图片既能节省 HTTP 请求, 仅需几行代码即可实现我们想要的功能功能. github 上也有很多这种动画库, 有兴趣的同学可以搜一搜. 390 | 391 | ![anima-loading](./images/anima-loading.gif) 392 | 393 | [点击此链接跳转至 codepen demo](https://codepen.io/anran758/pen/dmOPdO) 394 | 395 | ### [image] 居中裁剪展示图片 396 | 397 | 我们经常能遇到这种情景, 做一个用户头像. 拿到的图片是一个长方形的长图, 但是我们并不需要这么长的图, 因此我们需要"裁剪". 这时我们只需设置图片中心为原点, 设置相应的宽高再加上圆角即可, 代码如下: 398 | 399 | ```css 400 | .user-info-box .avatar { 401 | width: 86px; 402 | height: 86px; 403 | border-radius: 50%; 404 | background: 50% / cover; 405 | background-color: #f1f1f1; 406 | background-image: url(https://avatars.githubusercontent.com/u/23024075?v=3); 407 | } 408 | ``` 409 | 410 | ![avatar middle](./images/avatar-1.png) 411 | 412 | 其中`background: 50%/cover`是关键, 这一个方法同时也可以适用于其他有图片的场景. 413 | 414 | [点击此链接跳转至 codepen demo](https://codepen.io/anran758/pen/WdOvRY/) 415 | 416 | ### [image] 悬浮头像动画 417 | 418 | 我们利用 css3 属性的`transform`对悬浮后的`border`进行旋转, 通过`transition`进行过度, 从而实现悬浮后的炫酷效果. 419 | 420 | ![avatar hover](./images/image-hover.gif) 421 | 422 | [点击此链接跳转至 codepen demo](https://codepen.io/anran758/pen/YapWKd) 423 | 424 | ### [image] 图像置灰 425 | 426 | css 中的 filter 可以将**模糊**或**颜色偏移**等图形效果应用于元素。其中 `grayscale` 函数可以设置图像的灰度: 427 | 428 | ```css 429 | .image { 430 | filter: grayscale(100%); 431 | } 432 | ``` 433 | 434 | ![example](../../_images/css-grayscale-example.png) 435 | 436 | ### [table] 表格设置间隙 437 | 438 | 使用 `border-spacing` 属性,该属性只有在 `border-collapse` 值是 `separate` 的时候生效。 439 | 440 | ```css 441 | .table { 442 | /* 表格中相邻单元格共享边框 */ 443 | border-collapse: separate; 444 | border-spacing: 16px 8px; 445 | } 446 | ``` 447 | 448 | ### 图形绘制 449 | 450 | 可以利用`css`属性来绘制常见的图形, 来完成一些设计所需,同时还可以节省图片的 HTTP 请求。 451 | 452 | [点击此链接跳转至 codepen demo](https://codepen.io/anran758/pen/jxjGyo) 453 | 454 | ![form](./images/drawing_graphics.png) 455 | 456 | ## 技术细节 457 | 458 | ### 继承性与通配符 459 | 460 | 使用通配符(`*`), 意味着页面中的所有的标签都会加上通配符里的属性. 然而很多人在使用的时候, 尤其在不了解属性特性的情况下, 容易造成很大性能浪费. 461 | 462 | 就比如说有些属性是具有**继承性**的, 在下例中``标签在没有制定`color`属性时, 就逐级向上找到`.container`的`color`继承. 463 | 464 | ```html 465 | 470 | 471 |
472 | 这里是div容器内 473 |

这是一个演示的例子

474 |
475 | ``` 476 | 477 | 这意味着如果我们用通配符设置这些属性时, 会徒劳给页面的增加没必要的性能负担. 478 | 479 | 再来看一个典型的例子. iOS 系统下, 点击一个链接或者通过 Javascript 定义的可点击元素的时候, 会出现一个半透明的灰色背景(就是所谓会闪一下), 这时`可以设置-webkit-tap-highlight-color`为透明来重置这个"BUG", 这里属性没用错, 但问题就出现在错误的使用了通配符. 如下图: 480 | 481 | ![wildcard](./images/wildcard.png) 482 | 483 | 还有一种就是使用`* {margin: 0; padding: 0}`则就过分了, `H1 ~ 6`标签本身就没有默认`padding`, 你特么非要给人家重置一下. `
  • `就更无辜了, 没有默认的`padding`和`margin`也要被批斗. 因此我们应该避免使用通配符. 484 | 485 | ### 清除浮动 486 | 487 | Nicholas C. Zakas( 尼古拉斯)提出了个更好清除浮动的一个方案, 即: 488 | 489 | 设置 `display: table;` 可以创建一个匿名的表格单元,同时这个匿名的表格单元会触发 `BFC(block formatting context)` 来清除浮动。 490 | 491 | ```css 492 | .clearfix:before, 493 | .clearfix:after { 494 | content: ""; 495 | display: block; 496 | } 497 | 498 | .clearfix:after { 499 | clear: both; 500 | } 501 | ``` 502 | 503 | ### z-index design 504 | 505 | css 中的 z-index 可以控制元素的层级,在多人项目开发中很容易产生相互覆盖的情况,所以在事先需要对该部分做一个设计约束。 506 | 507 | 多数情况下,普通的元素若需要修改层级仅仅需要设置为低等级即可,如 `z-index: 1`。若设计全局组件为了避免业务代码的侵入,会设置一个大数值。以下变量可作为参考: 508 | 509 | ```scss 510 | $zindex-dropdown: 1000 !default; 511 | $zindex-sticky: 1020 !default; 512 | $zindex-fixed: 1030 !default; 513 | $zindex-modal-backdrop: 1040 !default; 514 | $zindex-modal: 1050 !default; 515 | $zindex-popover: 1060 !default; 516 | $zindex-tooltip: 1070 !default; 517 | ``` 518 | 519 | ## 动画与特效 520 | 521 | - [使用一个 div 做动画](https://a.singlediv.com/) 522 | - [button 悬浮特效](https://codepen.io/anran758/pen/LejpaB/) 523 | - [loading.io](https://loading.io/): 商用的 loading 特效 524 | -------------------------------------------------------------------------------- /docs/develop/css/design/botton/css/reset.css: -------------------------------------------------------------------------------- 1 | /* 简化reset, 对常用元素进行简化 */ 2 | 3 | body, 4 | dl, 5 | dd, 6 | h1, 7 | h2, 8 | h3, 9 | h4, 10 | h5, 11 | h6, 12 | p, 13 | form, 14 | ol, 15 | ul { 16 | margin: 0; 17 | } 18 | 19 | ol, 20 | ul { 21 | padding: 0; 22 | list-style: none; 23 | } 24 | 25 | a { 26 | text-decoration: none; 27 | } 28 | 29 | body { 30 | font: 12px Helvetica Neue, Helvetica, Arial, Microsoft Yahei, Hiragino Sans GB, Heiti SC, WenQuanYi Micro Hei, sans-serif; 31 | } 32 | 33 | .clearfix:before, 34 | .clearfix:after { 35 | content: " "; 36 | display: block; 37 | } 38 | 39 | .clearfix:after { 40 | clear: both; 41 | } -------------------------------------------------------------------------------- /docs/develop/css/design/botton/css/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | transition: all 0.6s ease; 3 | } 4 | 5 | html, 6 | body { 7 | box-sizing: border-box; 8 | height: 100%; 9 | width: 100%; 10 | } 11 | 12 | body { 13 | font-family: "Roboto", sans-serif; 14 | font-weight: 400; 15 | background: #e1332d; 16 | } 17 | 18 | .buttons { 19 | display: table; 20 | height: 100%; 21 | width: 100%; 22 | } 23 | 24 | .container { 25 | display: table-cell; 26 | padding: 1em; 27 | text-align: center; 28 | vertical-align: middle; 29 | } 30 | 31 | h1 { 32 | color: #fff; 33 | font-size: 1.25em; 34 | font-weight: 900; 35 | margin: 0 0 2em; 36 | } 37 | 38 | @media (min-width: 450px) { 39 | h1 { 40 | font-size: 1.75em; 41 | } 42 | } 43 | 44 | @media (min-width: 760px) { 45 | h1 { 46 | font-size: 3.25em; 47 | } 48 | } 49 | 50 | @media (min-width: 900px) { 51 | h1 { 52 | font-size: 5.25em; 53 | margin: 0 0 1em; 54 | } 55 | } 56 | 57 | .btn { 58 | position: relative; 59 | width: 100%; 60 | max-width: 160px; 61 | margin: 0 auto 2em; 62 | line-height: 45px; 63 | color: #fff; 64 | cursor: pointer; 65 | font-size: 16px; 66 | font-weight: 400; 67 | vertical-align: middle; 68 | text-transform: uppercase; 69 | } 70 | 71 | @media (min-width: 400px) { 72 | .btn { 73 | display: inline-block; 74 | margin-right: 2.5em; 75 | } 76 | .btn:nth-of-type(even) { 77 | margin-right: 0; 78 | } 79 | } 80 | 81 | @media (min-width: 600px) { 82 | .btn:nth-of-type(even) { 83 | margin-right: 2.5em; 84 | } 85 | .btn:nth-of-type(5) { 86 | margin-right: 0; 87 | } 88 | } 89 | 90 | .btn:hover { 91 | text-decoration: none; 92 | } 93 | 94 | .btn-1 { 95 | background: #e02c26; 96 | font-weight: 100; 97 | } 98 | 99 | .btn-1 svg { 100 | height: 45px; 101 | left: 0; 102 | position: absolute; 103 | top: 0; 104 | width: 100%; 105 | } 106 | 107 | .btn-1 rect { 108 | fill: none; 109 | stroke: #fff; 110 | stroke-width: 2; 111 | stroke-dasharray: 422, 0; 112 | } 113 | 114 | .btn-1:hover { 115 | background: rgba(225, 51, 45, 0); 116 | font-weight: 900; 117 | letter-spacing: 1px; 118 | } 119 | 120 | .btn-1:hover rect { 121 | stroke-width: 5; 122 | stroke-dasharray: 15, 310; 123 | stroke-dashoffset: 48; 124 | -webkit-transition: all 1.35s cubic-bezier(0.19, 1, 0.22, 1); 125 | transition: all 1.35s cubic-bezier(0.19, 1, 0.22, 1); 126 | } 127 | 128 | .btn-2 { 129 | letter-spacing: 0; 130 | } 131 | 132 | .btn-2:hover, 133 | .btn-2:active { 134 | letter-spacing: 5px; 135 | } 136 | 137 | .btn-2:after, 138 | .btn-2:before { 139 | position: relative; 140 | display: block; 141 | width: 0; 142 | border: 1px solid rgba(255, 255, 255, 0); 143 | bottom: 0px; 144 | content: " "; 145 | margin: 0 auto; 146 | backface-visibility: hidden; 147 | transition: all 280ms ease-in-out; 148 | } 149 | 150 | .btn-2:hover:after, 151 | .btn-2:hover:before { 152 | width: 70%; 153 | border-color: #fff; 154 | backface-visibility: hidden; 155 | transition: width 350ms ease-in-out; 156 | } 157 | 158 | .btn-2:hover:before { 159 | bottom: auto; 160 | top: 0; 161 | width: 70%; 162 | } 163 | 164 | .btn-3 { 165 | border: 1px solid #da251f; 166 | font-weight: 900; 167 | letter-spacing: 1px; 168 | background: #e3403a; 169 | transition: all 150ms linear; 170 | box-shadow: 0px 2px 0 #d6251f, 2px 4px 6px #e02a24; 171 | } 172 | 173 | .btn-3:hover { 174 | border: 1px solid rgba(0, 0, 0, 0.05); 175 | color: #ec817d; 176 | text-decoration: none; 177 | background: #e02c26; 178 | text-shadow: -1px -1px 0 #c2211c; 179 | box-shadow: 1px 1px 2px rgba(255, 255, 255, 0.2); 180 | transition: all 250ms linear; 181 | } 182 | 183 | .btn-4 { 184 | position: relative; 185 | border: 1px solid; 186 | overflow: hidden; 187 | } 188 | 189 | .btn-4 span { 190 | z-index: 20; 191 | } 192 | 193 | .btn-4:after { 194 | content: ""; 195 | position: absolute; 196 | top: -50px; 197 | width: 50px; 198 | height: 155px; 199 | left: -75px; 200 | background: #fff; 201 | opacity: 0.2; 202 | transform: rotate(35deg); 203 | transition: all 550ms cubic-bezier(0.19, 1, 0.22, 1); 204 | z-index: -10; 205 | } 206 | 207 | .btn-4:hover:after { 208 | left: 120%; 209 | transition: all 550ms cubic-bezier(0.19, 1, 0.22, 1); 210 | } 211 | 212 | .btn-5 { 213 | border: 0 solid; 214 | box-shadow: inset 0 0 20px rgba(255, 255, 255, 0); 215 | outline: 1px solid; 216 | outline-color: rgba(255, 255, 255, 0.5); 217 | outline-offset: 0px; 218 | text-shadow: none; 219 | transition: all 1250ms cubic-bezier(0.19, 1, 0.22, 1); 220 | } 221 | 222 | .btn-5:hover { 223 | border: 1px solid; 224 | box-shadow: inset 0 0 20px rgba(255, 255, 255, 0.5), 225 | 0 0 20px rgba(255, 255, 255, 0.2); 226 | outline-color: rgba(255, 255, 255, 0); 227 | outline-offset: 15px; 228 | text-shadow: 1px 1px 2px #427388; 229 | } 230 | -------------------------------------------------------------------------------- /docs/develop/css/design/botton/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | botton hover 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
    17 |
    18 |

    Button Hover Effects

    19 | 20 | 21 | 22 | Hover 23 | 24 | 25 | Hover 26 | 27 | 28 | Hover 29 | 30 | 31 | 32 | Hover 33 | 34 | 35 | 36 | Hover 37 | 38 | 39 |
    40 |
    41 | 42 | 43 | -------------------------------------------------------------------------------- /docs/develop/css/design/images/auto-width.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/develop/css/design/images/auto-width.gif -------------------------------------------------------------------------------- /docs/develop/css/design/images/flexbox-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/develop/css/design/images/flexbox-1.gif -------------------------------------------------------------------------------- /docs/develop/css/design/images/flexbox-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/develop/css/design/images/flexbox-2.gif -------------------------------------------------------------------------------- /docs/develop/css/images/anima-loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/develop/css/images/anima-loading.gif -------------------------------------------------------------------------------- /docs/develop/css/images/avatar-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/develop/css/images/avatar-1.png -------------------------------------------------------------------------------- /docs/develop/css/images/background-more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/develop/css/images/background-more.png -------------------------------------------------------------------------------- /docs/develop/css/images/drawing_graphics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/develop/css/images/drawing_graphics.png -------------------------------------------------------------------------------- /docs/develop/css/images/image-hover.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/develop/css/images/image-hover.gif -------------------------------------------------------------------------------- /docs/develop/css/images/nav-anima.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/develop/css/images/nav-anima.png -------------------------------------------------------------------------------- /docs/develop/css/images/nav-split.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/develop/css/images/nav-split.png -------------------------------------------------------------------------------- /docs/develop/css/images/wildcard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anran758/front-end-lab/d5e6bb152e0a52d3d66a4e8c769a7318c4944930/docs/develop/css/images/wildcard.png -------------------------------------------------------------------------------- /docs/develop/css/reset.css: -------------------------------------------------------------------------------- 1 | /* 简化reset, 对常用元素进行简化 */ 2 | 3 | body, 4 | dl, 5 | dd, 6 | h1, 7 | h2, 8 | h3, 9 | h4, 10 | h5, 11 | h6, 12 | p, 13 | form, 14 | ol, 15 | ul { 16 | margin: 0; 17 | } 18 | 19 | ol, 20 | ul { 21 | padding: 0; 22 | list-style: none; 23 | } 24 | 25 | a { 26 | text-decoration: none; 27 | } 28 | 29 | body { 30 | font: 14px Helvetica Neue, Helvetica, Arial, Microsoft Yahei, Hiragino Sans GB, Heiti SC, WenQuanYi Micro Hei, sans-serif; 31 | } 32 | 33 | .clearfix:before, 34 | .clearfix:after { 35 | content: " "; 36 | display: block; 37 | } 38 | 39 | .clearfix:after { 40 | clear: both; 41 | } 42 | -------------------------------------------------------------------------------- /docs/develop/css/theory.md: -------------------------------------------------------------------------------- 1 | # CSS 原理 2 | 3 | 一些值得注意的 rule 或 defect: 4 | 5 | 1. css 选择符是从右至左进行匹配的,为了浏览器在匹配 rule 时消耗过的时间应避免嵌套太高层级,**建议最高不超过 3 层**。 6 | 2. 了解哪些属性可以通过继承而来,避免重复指定规则。 7 | 3. 滚动容器避免使用 `padding-bottom` 进行留白,IOS 低版本会直接忽略掉。除此之外 `IE`, 低版本的 `firefox` 据说也有这种情况。 8 | 9 | 在中文版 chrome 浏览器下, 最小的字号会有一个下限, 这个下限会强制改变小于该值的文字大小。使其成为默认浏览器最小的值。中文版最低是 `12px`,英文版则是 `10px`。 10 | 11 | **相关资料:** 12 | 13 | - [normalize 与 reset 的取舍](https://anran758.github.io/blog/2017/10/15/%E6%B5%85%E8%B0%88Normalize%E4%B8%8Ereset/) 14 | 15 | ## margin 16 | 17 | ### marin 百分比计算 18 | 19 | 普通元素的 `marin` 的百分比是根据父元素的宽度来计算的。例如: 20 | 21 | ```css 22 | .parents { 23 | width: 600px; 24 | } 25 | 26 | img { 27 | margin: 10%; 28 | } 29 | ``` 30 | 31 | 那么子元素的 `margin` 计算后值为: `600px * 10% = 60px`。 32 | 33 | 绝对定位计算方式是相同的,只不过它不是相对父元素,而是相对于第一个定位元素 (`relative/absolute/fixed`) 的宽度计算的。 34 | 35 | ### margin 重叠通常特性 36 | 37 | 1. block 水平元素(不包括 `float` 和 `absolute` 元素) 38 | 2. 不考虑 `writing-mode`,只发生在垂直方向 (`margin-top` / `margin-bottom`) 39 | 40 | ### margin 重叠的场景 41 | 42 | 1. 相邻的兄弟元素 43 | 2. 父级和第一个 / 最后一个子元素 44 | 3. 空的 block 元素 45 | 46 | ### 父子 margin 重叠的其他条件 47 | 48 | **margin-top 重叠**: 49 | 50 | 1. 父元素非块状格式化上下文元素 51 | 2. 父元素没有 `border-top` 设置 52 | 3. 父元素没有 `padding-top` 值 53 | 4. 父元素和第一个子元素之间没有 `inline` 元素分隔 54 | 55 | **margin-bottom 重叠**: 56 | 57 | 1. 父元素非块状格式化上下文元素 58 | 2. 父元素没有 `border-bottom` 设置 59 | 3. 父元素没有 `padding-bottom` 值 60 | 4. 父元素和最后一个子元素之间没有 `inline` 元素分隔 61 | 5. 父元素没有 `height`、`min-height`、`max-height` 限制 62 | 63 | ### 空 block 元素重叠 64 | 65 | 1. 元素没有 `border`/`padding`/`inline` 元素; 66 | 2. 没有设置 `height`/`min-height`; 67 | 68 | ### margin 重叠计算规则 69 | 70 | 1. 正正取大值 71 | 2. 正负值相加 72 | 3. 正负最负值 73 | 74 | ### 清除 margin 重叠 75 | 76 | 1. -加入 css 属性 `overflow: hidden;`- 使父元素触发BFC,包括但不限于overflow:hidden;display:inline-block;等等 77 | 2. 加入边框 (`border`) 属性; 78 | 3. 加入 `padding-top` 79 | 4. 加入内联元素,如 ` ` 80 | 5. 限制高度 `height` 81 | 82 | ### 善用 margin 重叠 83 | 84 | ```css 85 | .list { 86 | margin-top: 12px; 87 | margin-bottom: 12px; 88 | } 89 | ``` 90 | 91 | 写垂直布局的时候,利用 margin 重叠 (外边距塌陷) 的特性,在容器上下加上 margin 会更具有稳定性,哪怕移除元素或者元素没加载出来都不会破坏布局。 92 | 93 | ### margin 分配空间 94 | 95 | `block` 元素可以使用 `margin` 分配剩余空间。 96 | 97 | 1. `margin:auto` 就是为了填充而设置的。 98 | 2. 如果一侧值是定值,另一侧是 auto,则 auto 为剩余值的空间大小 99 | 3. 如果两侧均是 `auto`,则平分剩余空间大小 100 | 101 | 元素上设置 `position: absolute;`、`width/height`,`left/right` 后可以通过 `margin: auto` 居中,兼容性: `IE8+`。 102 | 103 | ```css 104 | .element { 105 | width: 400px; 106 | height: 400px; 107 | position: absolute; 108 | left: 0; 109 | top: 0; 110 | right: 0; 111 | bottom: 0; 112 | margin: auto; 113 | } 114 | ``` 115 | 116 | ### margin 实现等高布局 117 | 118 | 通过 `margin-bottom` 改变空间大小,`padding-bottom` 将内容填充回来,这时候元素占据的空间就是真实占高度据的空间。 119 | 120 | 副作用是必须要父元素 `overflow:hidden` 限制它,让 `margin-bottom` 不会影响外面的布局。 121 | 122 | 127 | 128 | ### margin 失效的情况 129 | 130 | 1. `inline` 元素的垂直 `margin` 无效。 131 | 2. `margin` 重叠 132 | 3. 元素处于 `display:table-cell` 或 `display:table-row` 133 | 4. `position: absolute` 与 `margin`。 134 | 135 | 绝对定位的 `margin` 值一直有效,只是表现形式不像普通元素那样。绝对定位元素是脱离文档流,它和相邻元素没有任何关系。可以理解为一个在地下,一个在天上,不在同一个维度) 136 | 137 | 5. 鞭长莫及导致的 margin 无效。 138 | 6. 内联特性导致的 margin 无效。(在有 `height` 限制下,`-margin` 小到一定程度时,会受制于内联默认对齐特性给限制住) 139 | 140 | ## float 141 | 142 | **特性**:父元素没有设置固定高度,子元素设置了浮动,会使父元素高度坍塌。 143 | 144 | ### 关于标准文档流 145 | 146 | **文档流**是相对于盒子模型,**文本流**是相对于文子段落。文本流是从上到下,从左到右的顺序进行文字排版。 147 | 148 | 元素浮动后,会让它脱离文档流。也就是说当它后面还有元素时,其他元素会无视它所占据的区域,直接在其身下布局。 149 | 但是文字还会认同浮动元素所占据的区域,围绕它布局,这意味着浮动元素脱离文档流但没有脱离文本流。 150 | 151 | 绝对定位元素脱离了文档流也脱离了文本流,文字都可以显示,这是**绝对定位和 float 的区别**。 152 | 153 | 总的来说,标准文档流=文档流+文本流。 154 | 155 | ## line-height 156 | 157 | `line-height` 的定义:行高,表示两行文字基线的距离。 158 | 159 | 1. 行高由于其继承性,影响无处不在,即使单行文本也不例外。 160 | 2. 行高只是幕后黑手,高度的表现不是行高,而是内容区域和行间距。 161 | 162 | ```css 163 | 内容区域高度 + 行间距 = 行高 164 | ``` 165 | 166 | 1. 内容区域高度只与字号以及字体有关,与 `line-height` 没有关系. 167 | 2. 在 `simsun(宋体)` 字体下,内容区域等于文字大小值。 168 | 169 | ```css 170 | font-size + 行间距 = line-height 171 | 172 | font-size: 240px; 173 | line-height: 360px; 174 | 行间距 = 360px - 240px = 120px; 175 | ``` 176 | 177 | ### 应用元素的差别 178 | 179 | - `line-height: 1.5` 所有可继承元素根据 `font-size` 重计算行高 180 | - `line-height: 150%/1.5em` 当前元素根据 `font-size` 计算行高,继承给下面的元素 181 | 182 | ### body 全局数值行高使用经验 183 | 184 | 面向用户: 匹配 `20px`的使用经验--方便心算 185 | 186 | ```css 187 | body { 188 | font-size: 14px; 189 | line-height: 20px; 190 | } 191 | ``` 192 | 193 | ### 消除图片底部间隙的方法 194 | 195 | 1. 图片块状化 - 无基线对齐 196 | 197 | ```css 198 | img { 199 | display: block; 200 | } 201 | ``` 202 | 203 | 2. 图片底线对齐 204 | 205 | ```css 206 | img { 207 | vertical-align: bottom; 208 | } 209 | ``` 210 | 211 | 3. 行高足够小 - 基线位置上移 212 | 213 | ```css 214 | .box { 215 | line-height: 0; 216 | } 217 | ``` 218 | 219 | ### middle 220 | 221 | `vertical-align: middle` 其实就是基线往上1/2高度。 222 | 223 | ## position relative 224 | 225 | ### relative 限制作用 226 | 227 | 1. 限制 left/top/right/bottom 定位; 228 | 2. 限制 z-index 层级; (相同relative不同层级,层级高的显示在前) 229 | 3. 限制 overflow 230 | 231 | ### relative 和定位 232 | 233 | 1. 相对自身 234 | 2. 无侵入 (无侵入定位的应用) 235 | 236 | top / bottom 和 left / right 对立属性同时存在会斗争,对立属性只有一个先来的会起作用 237 | 238 | ### relative 与 z-index 层级 239 | 240 | 1. 提高层叠上下文 241 | 2. 新建层叠上下文与层级控制 242 | 3. 设置 `position: relative` 的元素中 z-index 为 auto,不会限制内部 absolute 元素层叠问题. 243 | > :: IE6/IE7 auto 也会创建层叠上下文 (auto 不符合规范, 会出 bug) 244 | 245 | ### relative 的最小化影响原则 246 | 247 | 所谓 relative 的最小化影响原则,指的是尽量降低 relative 属性对其他元素或布局的潜在影响。 248 | 249 | 1. 尽量避免使用 relative 250 | 2. relative 最小化 251 | 252 | ## z-index 253 | 254 | ### z-index 的层级水平 255 | 256 | ![7 阶 z-index 层叠上下文](../../_images/z-index-stacking-level.png) 257 | 258 | 1. 层叠上下文 background/border 259 | 2. 负 z-index 260 | 3. block 块状水平盒子 261 | 4. float 浮动盒子 262 | 5. inline/inline-block 水平盒子 263 | 6. z-index: auto 或 z-index: 0 不依赖 z-index 的层叠上下文 264 | 7. 正 z-index 265 | 266 | ### z-index 的相关实践 267 | 268 | **最小化影响** 269 | 270 | - 目的: z-index 嵌套层叠关系混乱 271 | - 原因: 272 | 1. 元素的层叠水平主要由所在的层叠上下文决定; 273 | 2. IE7 z-index:auto 也会新建层叠上下文; 274 | - 做法: 275 | 1. 避免使用定位属性; 276 | 2. 定位属性从大容器平级分离为私有小容器; 277 | 278 | **避免滥用 z-index 层级** 279 | 280 | - 目的: 避免 z-index 混乱,一山比一山高的样式问题 281 | - 原因: 282 | 283 | 1. 多人维护以及后期维护; 284 | 285 | - 做法: 286 | 287 | 1. 对于非浮层元素 (e.g. 弹框),避免设置 z-index 值,z-index 值没有任何道理需要超过 2 288 | (避免弹框被非浮层元素覆盖) 289 | 290 | **组件层级计数器** 291 | 292 | - 目的: 避免浮层组件因 z-index 被覆盖的问题 293 | - 原因: 294 | 295 | 1. 总会遇到意想不到的高层级元素; 296 | 2. 组件的覆盖规则具有动态性; 297 | 298 | - 做法: 299 | 300 | 1. 组件层级计数器方法: 通过 js 获取 body 下子元素最大的 z-index 值, 然后最大值 + 1 301 | 302 | **可访问隐藏** 303 | 304 | z-index 负值元素在层叠上下文的背景之上, 其他元素之下. 305 | -------------------------------------------------------------------------------- /docs/develop/html/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebarDepth: 3 3 | --- 4 | 5 | 6 | 7 | # HTML 8 | 9 | - [SEO(搜索引擎优化)](#seo搜索引擎优化) 10 | - [标签](#标签) 11 | - [img](#img) 12 | - [video](#video) 13 | - [视频首屏最先加载方法](#视频首屏最先加载方法) 14 | - [引用视频播放失败](#引用视频播放失败) 15 | - [pre, code](#pre-code) 16 | - [属性](#属性) 17 | - [href](#href) 18 | - [已知问题](#已知问题) 19 | 20 | --- 21 | 22 | ## SEO(搜索引擎优化) 23 | 24 | 搜索引擎优化(SEO)是一种通过优化网站来提高网站在搜索引擎中的自然排名的技术。以下内容将帮助开发者和内容创作者理解并实现有效的SEO策略。 25 | 26 | **标题和描述** 27 | 28 | - **Title 标签:** 每个页面都应有一个独特且描述性强的标题。这是搜索引擎结果中最先显示的部分。 29 | - **Meta Description:** 提供一个页面内容的简洁概述。虽然它不直接影响排名,但好的描述可以提高点击率。 30 | 31 | **语义化标签** 32 | 33 | 使用HTML5中的语义化标签(如`
    `, `