吸顶处理兼容iOS和Android

目录

  • 问题抛出
  • 解决思路
    • sticky 定位
  • 解决办法
    • 判断设备类型
    • 安卓的吸顶处理
    • iOS的吸顶处理
    • 代码整合

问题抛出

当页面上滑时,顶部当导航需要进行吸顶处理。滑动过程使用scroll事件监听,当滚动的高度到底一定时,便设置样式 absolute:fixed;top:0px;以吸顶处理。

以上处理在安卓中时完全没有问题的,但是在iOS中缺会出现严重的样式问题:页面滚动过程中并不吸顶。

解决思路

针对iOS做兼容处理。iOS支持一个特殊的定位方式:absolute:sticky;//粘性定位。

sticky 定位

sticky 英文字面意思是粘,粘贴,所以可以把它称之为粘性定位。
position: sticky; 基于用户的滚动位置来定位。
粘性定位的元素是依赖于用户的滚动,在 position:relative 与 position:fixed 定位之间切换。
它的行为就像 position:relative; 而当页面滚动超出目标区域时,它的表现就像 position:fixed;,它会固定在目标位置。
元素定位表现为在跨越特定阈值前为相对定位,之后为固定定位。
这个特定阈值指的是 top, right, bottom 或 left 之一,换言之,指定 top, right, bottom 或 left 四个阈值其中之一,才可使粘性定位生效。否则其行为与相对定位相同。

div.sticky {
    position: -webkit-sticky; /* Safari */
    position: sticky;
    top: 0;
    background-color: green;
    border: 2px solid #4CAF50;
}

解决办法

判断设备类型

const judgeUserAgent = function () {
  if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) {
    return 'ios'
  } else if (/(Android)/i.test(navigator.userAgent)) {
    return 'android'
  } else {
    return 'pc'
  }
}

安卓的吸顶处理

positionSticky (el, top = 0, zIndex = 10) {
  const ot = el.offsetTop - top
  const fn = () => {
    const st = document.body.scrollTop || document.documentElement.scrollTop
    const fixStyle = `position: fixed;top: ${top}px;left: 0px;z-index: ${zIndex};`
    el.setAttribute('style', st > ot ? fixStyle : '')
  }
  fn()
  document.addEventListener('scroll', fn)
}

注意:安卓的fixed定位需要在滚动时没有问题,但是从relative定位切换到fixed定位后,会脱离文本流,使得切换fixed样式时页面会出现闪烁的情况。
解决办法:在需要的进行fixed定位的dom部分外边使用一个div将其包裹起来,并赋予相应的高度。

<div style="height:50px;">
	需要进行定位的dom部分<-->
	<div ref="postionDom">
		内容<-->		
	div>
div>
// vue中mounted钩子
mounted () {
	const el = this.$refs.postionDom
	this.positionSticky(el, 0, 10)
}

iOS的吸顶处理

positionSticky (el, top = 0, zIndex = 10) {
	if (window.screen.height === 812 && window.screen.width === 375) { // 在iphonex中打开
	  top += 20
	}
	const fixStyle = `position: -webkit-sticky;position: sticky;top: ${top}px;left: 0px;z-index: ${zIndex};`
	el.setAttribute('style', fixStyle)
	return
}
需要进行定位的dom部分<-->
<div ref="postionDom">
	内容<-->		
div>
// vue中mounted钩子
mounted () {
	const el = this.$refs.postionDom
	this.positionSticky(el, 0, 10)
}

代码整合

注意:兼容处理依然需要将不同设备类型的代码整合起来,这样易于调用与维护。
最终代码

const judgeUserAgent = function () {
  if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) {
    return 'ios'
  } else if (/(Android)/i.test(navigator.userAgent)) {
    return 'android'
  } else {
    return 'pc'
  }
}

const positionSticky = function(el, top = 0, zIndex = 10) {
  const userAgent = judgeUserAgent()
  if (userAgent === 'ios') {
  	// 虽然iOS中不需要在dom外边包裹一层,但是为了兼容android。
  	// 注意,sticky定位元素不能在其外层的dom元素使用div进行包裹起来,否则sticky会失效。定位到parentNode刚好也避过这个坑
    el = el.parentNode
    if (window.screen.height === 812 && window.screen.width === 375) { // 在iphonex中打开
      top += 20
    }
    const fixStyle = `position: -webkit-sticky;position: sticky;top: ${top}px;left: 0px;z-index: ${zIndex};`
    el.setAttribute('style', fixStyle)
    return
  }
  const ot = el.offsetTop - top
  const fn = () => {
    const st = document.body.scrollTop || document.documentElement.scrollTop
    const fixStyle = `position: fixed;top: ${top}px;left: 0px;z-index: ${zIndex};`
    el.setAttribute('style', st > ot ? fixStyle : '')
  }
  fn()
  document.addEventListener('scroll', fn)
}
<div style="height:50px;">
	需要进行定位的dom部分<-->
	<div ref="postionDom">
		内容<-->		
	div>
div>
// vue中mounted钩子
mounted () {
	const el = this.$refs.postionDom
	this.positionSticky(el, 0, 10)
}

你可能感兴趣的:(HTML,CSS,javascript,VUE)