html & css & javascript


此文收集一些 html & css 相关的内容

阻止IOS Safari默认解析电话号码

添加如下 meta 即可

<meta name="format-detection" content="telephone=no">

页面内容下边距

如果用 margin 给页面的内容增加一个主要内容的下边距, 虽然在 PC 端(模拟器) 看是生效的, 但是在很多手机上这部分下边距消失了, 只有用 padding 才是正道。

<main></main>

IE 11 不支持该标签(默认显示成了内联元素)

mobile tap highlight

在移动设备上按下时希望实现触碰元素的高亮效果, 可以给这个元素加 -webkit-tap-highlight-color; 但是有时需要别的效果, 这个时候可以使用 :active 伪类来实现——然而还是不够, 在 iOS safari 上如此设置仍然没有效果。 后来参考了 weui 的 demo, 发现它给 body 添加了一个空的事件 ontouchbegin, 配合 active 伪类, 成功的达成目标!

click delay

在移动设备上, 进行点击操作通常有300MS的延迟, 这300MS的延迟带来的操作体验大打折扣。看了weui的代码, 才发现还有 fastclick 这样一个方便的工具。使用方式如下:

import fastclick from 'fastclick'
fastclick.attach(document.body)

height of inline-block with overflow:hidden

给某 inline-block 添加溢出文本 ellipsis 的时候出现的问题, 发现如果加了 overflow:hidden 会平白无故的让父级容器变高一些。

解决办法是给这个 inline-block 添加 vertical-align: top, 原理在这里

ios webview 无法动态改变 title

有时会通过JS改变页面的 title, 但是据开发说 IOS WEBVIEW 可能需要一个加载动作来触发再次重命名TITLE, 实测IOS 微信中是这样的。以下是一种实现方式:

function setTitle (t) {
  setTimeout(() => {
    document.title = t
    const iframe = document.createElement('iframe')
    iframe.style.visibility = 'hidden'
    iframe.style.width = '1px'
    iframe.style.height = '1px'
    iframe.src = '/favicon.ico' // 这里
    iframe.onload = () => {
      setTimeout(() => {
        document.body.removeChild(iframe)
      }, 0)
    }
    document.body.appendChild(iframe)
  }, 0)
}

webview 右划返回历史纪录上一条

做前端路由的SPA的时候, 如果用的路由模式是 history, 那么在微信里无法通过右划返回历史纪录上一条; 但是如果用的是默认的 hash 模式的前端路由, 微信里就可以了。 这两种模式在 IOS safari 内都可以右划返回上一层, 但是用 vue 做的路由页面 transition 时, 会必然触发一次切换路由页面的动画, 会显得不那么好看了。

DIV 里的水平滚动条 平滑滚动

在移动端,DIV 里的水平滚动条表现的很迟钝,不平滑。幸好可以通过以下 css 解决[reference].(https://weblog.west-wind.com/posts/2013/jun/01/smoothing-out-div-scrolling-in-mobile-webkit-browsers):

.scroll-div {
  -webkit-overflow-scrolling: touch;
}

如果使用以下代码阻止了移动端页面的上下滚动回弹行为:

document.addEventListener('touchmove', function (e) {e.preventDefault()})

那么该 css 属性会失效。解决办法:设置 html body 的定位为 position: fixed,去掉阻止默认滚动的 js 即可。

保留滚动功能,但是隐藏滚动条

Reference

::-webkit-scrollbar {
    width: 0px;  /* remove scrollbar space */
    background: transparent;  /* optional: just make scrollbar invisible */
}
/* optional: show position indicator in red */
::-webkit-scrollbar-thumb {
    background: #FF0000;
}

此方式在 safari 上配合 -webkit-overflow-scrolling: touch; 使用会有bug,导致自定义的滚动条样式没有生效,比如无法隐藏滚动条等等。

Chrome 表单样式

Chrome 浏览器会自动给表单元素加上一些功能样式,比如自动完成、自动填充的黄色背景等等,有时候完全不需要这些功能。以下是一些解决办法(Reference):

  • 禁止自动完成:

    注意要给 form input 都加上 autocomplete="off", 否则 chrome 里可能救不起作用了。

    <form autocomplete="off">
      <input type="whatever" autocomplete="off"/>
    </form>
    
  • 禁止自动填充:

    Chrome 内遇到了带有密码输入框的表单,会自动尝试填充表单的内容。为了避免这种行为,不得不在表单开头添加两个隐藏的输入框,让 chrome 自作聪明的填在那里。

    <form>
      <input type="text" style="display:none;"/>
      <input type="password" style="display:none;"/>
      <input type="text" value="" autocomplete="off"/>
      <input type="password" value="" autocomplete="off"/>
    </form>
    
  • 自动填充区域的黄色背景:

    不得不说自动填充区域的默认的黄色背景简直丑的让人难以忍受,好在可以通过样式解决。

    input:-webkit-autofill {
      -webkit-box-shadow: 0 0 0 500px white inset;
    }
    

xhr post 请求弹出下载

通过 xmlHttpRequest 下载文件要注意以下几点:

  • xhr 的响应头通常会设置成 content-disposition: attachment;, 可以藉由此来判断是否是文件下载的逻辑;

  • xhr 的响应体如果不是 blob 对象(字符串), 需要通过 new Blob([xhr.response]) 手动生成 blob

  • 有了 blob 对象,就可以通过 a 标签的 download 属性设置自动弹出下载或类似的功能了。

  • 按照这种方式生成的 csv 文件用 excel 打开,中文字符会变成乱码,据说是因为文件头里缺失了 UTF-8 BOM(byte-order-mark, 字节顺序标记,用以标示文件采用哪种格式的编码)。查询得知UTF-8的 BOM 十六进制表示为 EF BB BF, 因此可以手动插入这一段 BOM: var blob = new Blob([new Uint8Array([0xEF, 0xBB, 0xBF]), 'Text Content'])。这样一来, excel 打开中文字符都是正确显示的了。

完整的流程处理如下:

let res = xhr.response
let disposition = decodeURIComponent(xhr.getResponseHeader('content-disposition'))
if (disposition && disposition.indexOf('attachment') !== -1) {
  //  https://stackoverflow.com/questions/16086162/handle-file-download-from-ajax-post/23797348#23797348
  let filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/
  let matches = filenameRegex.exec(disposition)
  let filename = Date.now() + '.csv'  //  这里定义一个默认的名字
  if (matches != null && matches[1]) {
    filename = matches[1].replace(/['"]/g, '')
  }
  let type = xhr.getResponseHeader('content-type')
  let blob = (res instanceof window.Blob) ? res : new window.Blob([new Uint8Array([0xEF, 0xBB, 0xBF]), res], {type})
  resolve({
    blob,
    filename
  })
  if (typeof window.navigator.msSaveBlob !== 'undefined') {
    // IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed."
    window.navigator.msSaveBlob(blob, filename)
  } else {
    let URL = window.URL || window.webkitURL
    let downloadUrl = URL.createObjectURL(blob)

    if (filename) {
      // use HTML5 a[download] attribute to specify filename
      let a = document.createElement('a')
      // safari doesn't support this yet
      if (typeof a.download === 'undefined') {
        window.location = downloadUrl
      } else {
        a.href = downloadUrl
        a.download = filename
        document.body.appendChild(a)
        a.click()
      }
    } else {
      window.location = downloadUrl
    }
    window.setTimeout(function () { URL.revokeObjectURL(downloadUrl) }, 100) // cleanup
  }
} else {
  try {
    res = JSON.parse(res)
  } catch (e) {
    throw e
  }
  resolve(res)
}

Chrome 跨域

有以下两种方式:

  • 使用 chrome 插件 Allow-Control-Allow-Origin: *。用这种方式会给所有请求自动添加上跨域的请求头,当跨域发生的时候,浏览器会先发送 OPTIONS 请求确认跨域,服务器同意之后才会发送真正的请求。如果服务器不同意或者没有设置对 OPTIONS 的成功响应,跨域仍会失败。

  • 完全关闭 chrome后, 使用命令启动:

    open -a Google\ Chrome --args --disable-web-security --user-data-dir
    

    通过这种方式是不会发送 OPTIONS 请求的,浏览器完全禁用了这个安全措施。