# 一些遇到过的问题

# 目录

# CSS

# Q: 如何更直观更方便地调试元素的尺寸与布局

  • 情况:

    有许多的元素(例如布局元素div或者span),我们一般不能直观地看到它们的大小、位置,只能通过F12去手动检查。

  • 技巧:

    给所有元素或者某些元素(如div)画上一个框,这样就能够清晰地看出每个元素的情况了。

    * {
      outline: red solid 1px;
      /* 使用border效果类似,但outline不会增加元素大小,而border会 */
    }
    

# Q: 在父元素中单独放入<img>元素后,<img>底部或后面有空白怎么办

  • 原因:

    1. 在<a>元素或者<div>等元素下有一个匿名文本,该文本外存在一个匿名行级盒子,由于 line-height 存在使其有了高度。

      因为默认 vertical-alignbaseline 对齐的原因,<img>之类的inline-block元素会使得这个匿名盒子下沉,撑开一些距离,于是把父元素撑高了。

    2. HTML 文档中,换行或者空格会被翻译成一个空白的文本节点(#text),导致会出现一个空格跟在<img>后面的情况。

  • 解决办法(任选其一):

    • 消除掉匿名盒子的高度,给<a>设置line-height: 0font-size: 0
    • 给两者vertical-align: top,让其top对齐,而不是baseline对齐;
    • 如果<img>元素是单独一行的话,可以给<img>以display: block或者float: left,让它和匿名行级盒子不在一个布局上下文中,也就不存在行级盒。<img>是行内元素,默认为 inline-block,与文本的默认行为类似,下边缘是与基线对齐,而不是紧贴容器下边缘。
    • 对于多个inline-block元素之间的空格,可以使用letter-spacing: -4px(字符之间的间距)或word-spacing: -4px(单词之间的间距)。

# Q: display: none、visibility: hidden、opacity: 0 之间的区别

三者都可以将元素隐藏,但存在区别如下:

属性 解释 空间占据 子元素继承 事件绑定可否触发 过渡动画能否作用
display: none 彻底消失 ✘,父元素不在了,子元素也不会显示
visibility: hidden 视觉上不可见 ✔,如果设置子元素可见则仍然可以使子元素显示
opacity: 0 透明度为 0 ✔,子元素无法通过设置 opacity 值显示

# Q: 内联元素之间有间隙

  • 原因:

    在 HTML 中,内联元素是类似于当作文本处理的。两个内联元素的 HTML 标签之间如果有换行,则会将换行符自动转换为一个空格。

  • 解决办法:

    元素标签之间不换行即可。如果你的内联元素是inline-block,还可以给父元素设置font-size: 0


# Q: 如何隐藏滚动条

  • 情况:

    对于一些固定尺寸的窗口需要塞入超过窗口大小的内容时,overflow: scroll是个不错的选择,但很多时候其产生的滚动条并不美观,于是便需要想办法将滚动条隐藏起来。

  • 解决办法:

    .scroll-area {
      overflow: scroll;
      /* IE10/Edge 去除滚动条 */
      -ms-overflow-style: none;
      /* firefox 64 隐藏滚动条 */
      scrollbar-color: transparent transparent;
      /* firefox 64 去除滚动条 */
      scrollbar-width: none;
    }
    
    /* Chrome 去除滚动条 */
    .scroll-area::-webkit-scrollbar {
      width: 0;
      height: 0;
    }
    

    其中“隐藏滚动条”代表只能将滚动条透明化,其仍然能被点击到,且占据原有的空间,只是视觉上不可见。


# Q: 如何实现图片在给定宽高的容器里不变形地覆盖整个容器

  • 情况:

    每当使用图片时往往会采用 img 标签,但仅通过设置 img 标签往往并不能兼顾宽度自适应与高度自适应。

  • 解决办法:

    用 background 设置图片的方式可以很容易地实现该需求。

    可以使用这样的语法:

    /* background: <bg-image> <position>/<bg-size> <repeat-style> */
    .image {
      background: url(imgs/img.jpg) center/cover no-repeat;
    }
    

    其中,background-size只能跟在position后面,中间用斜杠隔开。

    center代表居中,cover代表覆盖。

    如果background-size使用contain值,则为包含,效果与max-width: 100%; max-height: 100%;相类似。


# Q: hover 某元素使另一元素遮挡住该元素而导致闪烁怎么办

  • 情况:

    有时候我们需要实现鼠标悬停在某元素上时,该元素变为另外一个元素的效果,但另外一个元素如歌出现在该元素的上面,则相当于将鼠标与该元素隔开,使得该效果失效。

  • 解决方法:

    使用 JavaScript 是一种思路,但更好的方法是直接使用 CSS3 相应的属性pointer-events

    语法:

    pointer-events: auto(默认值) | none;
    // 以下值仅对SVG元素有效
    pointer-events: visiblepainted | visiblefill | visiblestroke | visible | painted | fill | stroke | all
    

    像 mouseover 这样的效果,都是由光标产生的事件,如果不想让新出现的元素遮挡住旧元素,可以设置:

    .new-element {
      pointer-events: none;
    }
    

    当值为none时,该元素就会不再与鼠标产生任何交互,鼠标悬停的判定会穿透该元素至下层。


# Q: 长文本超长打点

  • 单行文本超长打点(例如过长的昵称)

    .text {
      // 不换行
      white-space: nowrap;
      // 内容溢出隐藏(因为文本不换行导致的溢出不会算在容器宽度里)
      overflow: hidden;
      // 文本溢出使用省略符代替(...)
      text-overflow: ellipsis;
    }
    
  • 多行文本超长打点

    // 溢出隐藏
    overflow: hidden;
    // 弹性伸缩盒子模型
    display: -webkit-box;
    // 文本溢出使用省略符代替
    text-overflow: ellipsis;
    // 设置伸缩盒对象的子元素的排列方式
    -webkit-box-orient: vertical;
    // 限制在一个块元素显示的文本的行数(可修改)
    -webkit-line-clamp: 2;
    

    多行文本超长打点的兼容性在 IE11 以上,有需要考虑兼容性的情况则可以参考 Clamp.js (opens new window)(一个封装好的多行溢出打点库)


# JavaScript

不小心就归到了 CSS 部分中来了,先暂时放在这边叭

# Q: 将内容复制到用户的剪贴板上

  • 情况:

    想要实现用户点击按钮即可复制文本的效果。

  • 实现方法:

    js 提供了execCommand方法,它允许使用命令来操纵可编辑区域的内容。

    虽然表面上和我们想要达到的效果并没有直接关系,但该方法有一个参数——copy,可以让我们对可编辑区域中已经选中的文本内容执行复制操作。

    如果想要实现的效果不是从编辑区域中获取要复制的文本,则可以构造一个带有我们想要的文本的input元素添加到页面中,选中并复制完后立即移除该元素即可。

    代码如下:

    const btn = document.querySelector('#btn');
    btn.addEventListener('click', () => {
      // 创建可编辑区域
      const input = document.createElement('input');
      document.body.appendChild(input);
      // 设置输入框的内容(会被复制)
      input.setAttribute('value', '复制的内容');
      // 设置输入框为只读属性,避免唤起手机键盘
      input.setAttribute('readonly', 'readonly');
      // 选中输入框内容
      input.select();
      // 如遇 input.select() 未选择到文本内容的情况,试下下面的代码
      // input.setSelectionRange(0, 9999);
      // 执行复制操作
      if (document.execCommand('copy')) {
        document.execCommand('copy');
        console.log('复制成功');
      }
      // 移除该元素
      document.body.removeChild(input);
    });
    

    还有第三方库方法:clipboard.js,这里不做赘述。


# Q: JavaScript 获取不到 CSS 设置的属性值

# Q: JavaScript 设置的样式覆盖不了 CSS 样式

  • 情况:

    问题 1:在 javascript 中访问elem.style.<attr>,得到的属性返回空;

    问题 2:在 javascript 中使用elem.style.<attr> = <val>为样式规则赋值,样式没有应用上。

  • 原因:

    问题 1:在 javascript 中访问元素的样式属性,虽然它是可读可写的,但它不能获得在其他地方(如 CSS)中设置的样式值。(联想到在 HTML 标签的 style 属性中设置样式与使用 CSS 引入样式的差别)

    问题 2:虽然 javascript 代码没有编写错,但 CSS 那边对相同的样式规则应用了不同的属性值,使得将 js 设置的样式给覆盖掉了。

  • 解决方法:

    1. 可以将 CSS 的样式转移到 JavaScript 代码中来设置,这样就便于管理相关的值了。

    2. 使用以下语句计算获得当前元素的样式并取得目标样式规则的值:

      getComputedStyle(<elem>, null).getPropertyValue(<prop-name>);
      

      旧 IE 使用 elem.currentStyle.getAttribute('style');

      但第 2 种方法不能设置样式属性值。


# Q: 替换 URL 参数的同时不刷新网页,让用户第二次访问与第一次不同

  • 情况:

    有时候我们会通过判断 URL 中是否存在某参数来执行一些逻辑,又需要让这个逻辑只执行一次(例如领红包),想要使用户刷新该页面时不会再执行一次领红包的行为,则需要将某些参数删除或者改变。

    最简单的替换 URL 思路是 location.href = newUrllocation.replace(newUrl),但当我们设置该值时浏览器会自动刷新页面,这对用户的体验是不好的。

  • 解决方法:

    借助 History 的 API History.replaceState() (opens new window) 可以实现该效果:

    function replaceUrl(href) {
      if (!href) {
        return;
      }
      if (history.replaceState) {
        history.replaceState(null, document.title, href);
      } else {
        // 兜底,仍然会刷新页面
        location.replace(href);
      }
    }
    

    replaceState 会替换当前 URL 栏上显示的地址,但是不会刷新页面,也不会检查 URL 的可访问性,当用户进入一个页面再回来、或者直接刷新页面,都以新的 URL 为准。

    唯一限制是替换的 URL 必须和原 URL 同源,否则会抛出异常。


# Q: more...


上次更新: 2020/6/16 10:49:47