letter-spacing+first-letter实现按钮文字隐藏

一、文不在长,有货则灵

图片式按钮的文字隐藏看来是大家都比较关注的一个问题(分享讨论、微博转发等可见一斑),text-indent负值为最常用方法,然问题有三:

  1. 较大的负值有性能问题,例如新浪/腾讯微博提交按钮的-9999em,大概12~16万像素的宽度,相对于100个显示器宽度,在低配Android pad上,尤其含动画效果的时候,会直接卡爆;
  2. FireFox浏览器下虚框。其实问题不大,overflow:hidden可修复;
  3. 不能应用在IE6/IE7伪inline-block水平元素上,否则元素会被text-indent拐走。

即使有人提出:

{ text-indent: 100%; white-spacing: nowrap; overflow: hidden; }

除了性能有所缓解,后面两个问题依旧存在。

二、法不在高,能用则行

上周分享,有同行提到另外一个隐藏之法,简称为:font: 0/0 a法。

释义为,字号大小0, 行高0,字体a是因为就一个字母,换成b也是OK的,实际并无a字体。日本高中社团要至少4个人才能成立,游泳社就3个人,于是就去田径队找了个旱鸭子来充数,这个旱鸭子就是这里的a.

一般要配合overflow: hidden使用。

实例顶千言,您可以狠狠地点击这里:font:0/0 a与按钮文字隐藏

CSS代码如下:

.btn {
    display: inline-block;
    width: 52px; height: 25px;
    border: 0;
    background: #f0f0f0 url(/study/image/flash_copy_btn.png);
    font: 0/0 a;
    overflow: hidden;    /* 抹掉a标签按钮最上面的小点 */
}

说明:

  1. 网上有说法是Chrome下需要添加color: transparent,不过据我win7 Chrome浏览器查看,没什么问题,因此CSS中无此声明;
  2. overflow: hidden用来解决IE6浏览器下,a元素等模拟标签下最顶部残存小点点的问题。
  3. 对于原生的button按钮元素,此方法表示无能为力,低版本IE浏览器下,小点点依旧存在,如下放大后的截图:
    IE6 按钮元素中的点点仍然存在

相比text-indent负值缩进,此方法优点在于可以应用在inline-block水平元素上;不足在于不能用在原生的button按钮元素上。

因此,还有改进余地以及寻找更好方法的动力。

三、斯是吾法,齐论德馨

此方法是我午饭后打瞌睡的时候想到的,一句话概括就是letter-spacing负值+first-letter伪元素负值实现。

对于新方法,先展示效果才能让别人有继续深入的兴趣。您可以狠狠地点击这里:letter-spacing/first-letter与按钮文字隐藏

IE6浏览器下的截图如下:
IE6浏览器下letter-spacing负值+first-letter伪类实现的文字隐藏效果

CSS代码如下:

.btn {
    display: inline-block;
    width: 52px; height: 25px;
    border: 0;
    background: #f0f0f0 url(/study/image/flash_copy_btn.png);
    letter-spacing: -3em;
    overflow: hidden;
}
.btn:first-letter {
    margin-left: -20em;
}

1. 关于letter-spacing负值
letter-spacing控制字符间距,可以是负值,可以让字符水平方向重叠,甚至倒序排列,如值为-2em时候。选择下面下拉值,可以看到不同letter-spacing大小对应效果:

更改letter-spacing大小:

我是测试文字!

于是,如果按钮text-alignleft的话,letter-spacing值在小于-2em的时候,字符都跑到了首字符的左侧(也就是在按钮的外面)。一旦按钮设置了overflow:hidden除了第一个字符,其余字符都隐藏了

2. 关于first-letter伪元素
first-letter伪元素与first-line伪元素实际是表兄弟关系,first-line可以实现IE6/IE7的单标签多背景效果,前不久刚介绍,那first-letter呢?

顾名思意,first-letter控制第一个字符的样式,IE5.5开始支持,支持的样式有(参考自MDN):

  • 所有字体相关属性:font, font-style, font-variant, font-weight, font-size, line-height以及font-family.
  • 所有背景相关属性:background-color, background-image, background-position, background-repeat, background-size, 以及background-attachment.
  • 所有margin相关属性:margin, margin-top, margin-right, margin-bottom, margin-left.
  • 所有padding相关属性:padding, padding-top, padding-right, padding-bottom, padding-left.
  • 所有border相关属性:缩写的border, border-style, border-color, border-width及普通书写的属性。
  • color属性。
  • text-decoration, text-transform, letter-spacing, word-spacing(合适情境下), line-height, float, vertical-align(只有当floatnone的时候)这些CSS属性们.

要隐藏第一个字符,我采用的就是margin负值。例如:

.btn:first-letter {
    margin-left: -20em;
}

于是,字符们全部都隐藏了

当然,还是有些需要说明的。

3. 其他一些说明:

  1. 此方法兼容IE6+, 适用于inline-block水平元素,且适用于button元素,不过,需要是下面这种写法:
    <button type="button/submit">按钮</button>

    而不能是这样子:

    <input type="button/submit" value="按钮" />
  2. 此方法受text-align属性影响。letter-spacing负值+first-lettermargin负值适用于text-align:left;的情况,如果按钮text-alignright,则letter-spacing以及first-lettermargin需要使用正值。

    值的大小其实没有定值。一般,letter-spacing绝对值大于2em可以,首字符margin可以大一些,demo中是-20em.

  3. 多个:first-letter伪元素不要使用逗号分隔,貌似会全部失效,应分开写使用逗号分隔的时候逗号前面一定要留一个空格,就跟众所周知的{前面要留有空格一样,否则,IE6浏览器会忽略这条声明:
    .btn:first-letter,
    .img:first-letter {
        margin-left: -20em;
    }
    
    .btn:first-letter ,    /* 逗号前需有1个空格 */
    .img:first-letter {
        margin-left: -20em;
    }
    

未大规模测试,欢迎反馈问题。

在实际应用的时候,我们可以把该功能的CSS独立出来,公共使用,例如:

.notext {
    text-align: left;
    letter-spacing: -3em;
    overflow: hidden;
}
.notext:first-letter {
    margin-left: -20em;
}

四、不是会两句古诗就了不起的

其实呢,如果不要兼顾原生button按钮,还可以使用padding撑开容器尺寸隐藏文字的方法,类似下面:

.btn {
    display: inline-block;
    padding-top: 25px;
    width: 52px; height: 0;
    background: #f0f0f0 url(/study/image/flash_copy_btn.png);
    overflow: hidden;
}

代码少,理解简单,兼容性还不错。就是不能用在正宗的按钮元素上(IE6/IE7直接隐藏抗议)。

转载于:https://www.cnblogs.com/FineDay/articles/3359424.html

<script lang="ts" setup> import { ref, onMounted } from 'vue' import Navigater from '@/components/Navigation/Navigater.vue' import {getTaskDetail} from '@/pages/taskDetail/api/index' import type { UploadFile } from 'element-plus' import { Edit,Delete, Download, Plus, ZoomIn} from '@element-plus/icons-vue' import type { FormInstance, FormRules } from 'element-plus' const route = useRoute() // 正确获取当前 route 实例 const id = ref() const taskDetail = ref()// 任务详情 const partyUserInfo = ref() const checked1 = ref(false) const addTxt1 = ref('') const container = ref(null) let scaleValue = 1 const getData = async (id) => { const res = await getTaskDetail({id:id}) taskDetail.value = res.data partyUserInfo.value = res.data.partyUserInfo console.log(partyUserInfo.value.avatar)//输出结果https://cdn.shenyantuling.com/prod/image/head/shutiao1.png } // 图片上传 const dialogImageUrl = ref('') const dialogVisible = ref(false) const disabled = ref(false) const handleRemove = (file: UploadFile) => { console.log(file) } const handlePictureCardPreview = (file: UploadFile) => { dialogImageUrl.value = file.url! dialogVisible.value = true } const handleDownload = (file: UploadFile) => { console.log(file) } // 表单校验 const ruleFormRef = ref<FormInstance>() const ruleForm = reactive({ // .... }) const handleResize = () => { const containerWidth = container.value.offsetWidth const containerHeight = container.value.offsetHeight const windowWidth = window.innerWidth const windowHeight = window.innerHeight // 计算缩放比例,保持内容完整显示 scaleValue = Math.min( windowWidth / containerWidth, windowHeight / containerHeight ) container.value.style.transform = `scale(${scaleValue})` container.value.style.transformOrigin = 'top left' } onMounted(() => { handleResize() window.addEventListener('resize', handleResize) id.value = route.query.id getData(id.value) }) onBeforeUnmount(() => { window.removeEventListener('resize', handleResize) }) </script> <template> <div class="scale-container" ref="container"> <div class="content"> <!-- 顶部 logo 导航栏 --> <Navigater class="top"></Navigater> <!-- 任务详情 --> <div class="wrap"> <div class="topBack"> <div class="return"> <img src="@/assets/navigater/return.png" alt=""> </div> <div class="title">任务详情</div> </div> <div class="taskBox"> <div class="taskLeft"> <!-- 发布者 --> <div class="publisherBox"> <div class="avatar"> <img :src=partyUserInfo.avatar alt=""> </div> <div class="info"> <div class="infoTop"> <div class="name">avatar</div> <img src="@/assets/navigater/task1.png" alt=""> <img src="@/assets/navigater/task1.png" alt=""> </div> <div class="dic"> The First Onchain Treasury Network for Web 3The First Onchain Treasury Network for Web 3The First Onchain Treasury Network for Web 3 </div> </div> </div> <!-- 任务 --> <div class="taskDic"> <div class="taskImg"> <img src="@/assets/navigater/task1.png" alt=""> </div> <div class="taskText"> <div class="taskTitle">任务标题:关注微博账号赠送3000积分积分赠送</div> <div class="botBox"> <div class="type">任务类型</div> <div class="copy"> <img src="@/assets/navigater/task2.png" alt=""> </div> </div> </div> </div> <div class="tip"> <img src="@/assets/navigater/task1.png" alt=""> <div class="tipTxt">Joinly 将在发放奖励前仔细检查,已提交的任务</div> </div> <div class="taskMain"> <div class="mainTop"> <img src="@/assets/navigater/task2.png" alt=""> <div class="mainTxt">关注 crazy crap在微博的账号,账号名称crazy crap</div> </div> <div class="main"> <el-form ref="ruleFormRef" style="max-width: 600px" :model="ruleForm" status-icon label-width="auto" class="demo-ruleForm" > <!-- :rules="rules" --> <el-card class="step"> <div class="stepTop"> <div class="stepTit"> <el-checkbox v-model="checked1" size="large" /> <div class="stepTxt">关闭微博关闭微博关闭微博关闭微博关闭微博关闭微博关闭微博关闭微博关闭微博关闭微博</div> </div> <el-button class="stepBtn" color="#715EFF" type="primary" :icon="Edit" disabled>保存修改</el-button> </div> <div class="stepMain"> <div class="title">添加图片</div> <el-upload action="#" list-type="picture-card" :auto-upload="false" :limit=3> <el-icon><Plus /></el-icon> <template #file="{ file }"> <div> <img class="el-upload-list__item-thumbnail" :src="file.url" alt="" /> <span class="el-upload-list__item-actions"> <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)" > <el-icon><zoom-in /></el-icon> </span> <span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file)" > <el-icon><Delete /></el-icon> </span> </span> </div> </template> </el-upload> <el-dialog v-model="dialogVisible"> <img w-full :src="dialogImageUrl" alt="Preview Image" /> </el-dialog> <div class="title">添加文字</div> <el-input class="addTxt" type="textarea" v-model="addTxt1" placeholder="请输入文字" /> </div> </el-card> <el-card class="step"> <div class="stepTop"> <div class="stepTit"> <el-checkbox v-model="checked1" size="large" /> <div class="stepTxt">关闭微博关闭微博关闭微博关闭微博关闭微博关闭微博关闭微博关闭微博关闭微博关闭微博</div> </div> <el-button class="stepBtn" color="#715EFF" type="primary" :icon="Edit" disabled>保存修改</el-button> </div> <div class="stepMain"> <div class="title">添加图片</div> <el-upload action="#" list-type="picture-card" :auto-upload="false" :limit=3> <el-icon><Plus /></el-icon> <template #file="{ file }"> <div> <img class="el-upload-list__item-thumbnail" :src="file.url" alt="" /> <span class="el-upload-list__item-actions"> <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)" > <el-icon><zoom-in /></el-icon> </span> <span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file)" > <el-icon><Delete /></el-icon> </span> </span> </div> </template> </el-upload> <el-dialog v-model="dialogVisible"> <img w-full :src="dialogImageUrl" alt="Preview Image" /> </el-dialog> <div class="title">添加文字</div> <el-input class="addTxt" type="textarea" v-model="addTxt1" placeholder="请输入文字" /> </div> </el-card> <el-card class="step"> <div class="stepTop"> <div class="stepTit"> <el-checkbox v-model="checked1" size="large" /> <div class="stepTxt">关闭微博关闭微博关闭微博关闭微博关闭微博关闭微博关闭微博关闭微博关闭微博关闭微博</div> </div> <el-button class="stepBtn" color="#715EFF" type="primary" :icon="Edit" disabled>保存修改</el-button> </div> <div class="stepMain"> <div class="title">添加图片</div> <el-upload action="#" list-type="picture-card" :auto-upload="false" :limit=3> <el-icon><Plus /></el-icon> <template #file="{ file }"> <div> <img class="el-upload-list__item-thumbnail" :src="file.url" alt="" /> <span class="el-upload-list__item-actions"> <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)" > <el-icon><zoom-in /></el-icon> </span> <span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file)" > <el-icon><Delete /></el-icon> </span> </span> </div> </template> </el-upload> <el-dialog v-model="dialogVisible"> <img w-full :src="dialogImageUrl" alt="Preview Image" /> </el-dialog> <div class="title">添加文字</div> <el-input class="addTxt" type="textarea" v-model="addTxt1" placeholder="请输入文字" /> </div> </el-card> </el-form> </div> </div> </div> <div class="taskRight"> </div> </div> </div> </div> </div> </template> <style scoped lang="scss"> .scale-container { width: 1920px; /* 设计稿宽度 */ position: absolute; display: block; top: 0; left: 0; .content { width: 100%; height: 100%; background-color: #000; display: block; .wrap{ width: 1552px; margin: 0 auto; .topBack{ display: flex; width: 1552px; height: 74px; justify-content: left; align-items: center; border-bottom: 1px solid #444; margin-bottom: 31px; .return{ width: 24px; height: 24px; margin-right: 10px; img{ width: 100%; height: 100%; } } .title{ font-family: PingFang SC; font-weight: 600; font-style: Semibold; font-size: 20px; color:#fff; line-height: 100%; letter-spacing: -0.3px; } } .taskBox{ display: flex; width: 1174px; margin: 0 auto; .taskLeft{ width: 787px; .publisherBox{ width: 787px; height:100px; display: flex; background-color: #232323; border-radius: 12px; padding: 16px; margin-bottom: 30px; .avatar{ width: 48px; height: 48px; margin-right: 16px; img{ width: 100%; height: 100%; border-radius: 50%; } } .info{ .infoTop{ display: flex; justify-content: left; align-items: center; .name{ font-family: PingFang SC; font-weight: 600; font-style: Semibold; font-size: 20px; color:#fff; line-height: 100%; letter-spacing: -0.3px; } img{ width: 16px; height: 16px; border-radius: 50%; margin-left: 8px; } } .dic{ width: 536px; margin-top: 14px; font-family: PingFang SC; font-weight: 400; font-style: Regular; font-size: 14px; line-height: 21px; letter-spacing: -0.3px; color:#A6A6A6; display: -webkit-box; /* 关键属性:弹性伸缩盒子 */ -webkit-box-orient: vertical; /* 排列方向:垂直 */ -webkit-line-clamp: 2; /* 限制行数:2行 */ overflow: hidden; /* 溢出隐藏 */ text-overflow: ellipsis; /* 溢出显示省略号 */ word-break: break-word; /* 长单词换行处理 */ } } } .taskDic{ width: 786px; height: 150px; top: 346px; left: 373px; display: flex; padding-top: 32px; border-top: 1px solid #444; .taskImg{ img{ width: 160px; height: 120PX; border-radius: 12px; } } .taskText{ color: #fff; margin-left: 23px; .taskTitle{ width: 546px; height: 80px; font-family: PingFang SC; font-weight: 600; font-style: Semibold; font-size: 26px; letter-spacing: -0.3px; // display: -webkit-box; /* 关键属性:弹性伸缩盒子 */ // -webkit-box-orient: vertical; /* 排列方向:垂直 */ // -webkit-line-clamp: 2; /* 限制行数:2行 */ // overflow: hidden; /* 溢出隐藏 */ // text-overflow: ellipsis; /* 溢出显示省略号 */ // word-break: break-word; /* 长单词换行处理 */ } .botBox{ display: flex; justify-content: space-between; align-items: center; width: 603px; .type{ width: 64px; height: 30px; text-align: center; font-family: PingFang SC; font-weight: 600; font-style: Semibold; font-size: 12px; line-height: 30px; letter-spacing: -0.3px; border-radius: 4px; background-color: #232323; } .copy{ width: 30px; height: 30px; img{ width: 100%; height: 100%; } } } } } .tip{ display: flex; justify-content: left; align-items: center; margin: 32px auto; img{ width: 16px; height: 16px; border-radius: 50%; margin-right: 10px; } .tipTxt{ color:#fff;font-family: PingFang SC; font-weight: 400; font-style: Regular; font-size: 14px; line-height: 100%; letter-spacing: -0.3px; } } .taskMain{ width: 787px; padding: 24px; border-radius: 12px; background-color: #232323; .mainTop{ display: flex; justify-content: left; align-items: center; margin-bottom: 23px; img{ width: 24px; height: 24px; border-radius: 4px; margin-right: 10px; } .mainTxt{ font-family: PingFang SC; font-weight: 600; font-style: Semibold; font-size: 18px; color:#fff; line-height: 100%; letter-spacing: -0.3px; } } .main{ .step{ width: 739px; background-color: #121212; border: 1px solid #121212; .stepTop{ width: 715px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #444; .stepTit{ display: flex; justify-content: space-between; align-items: center; .stepTxt{ font-family: PingFang SC; font-weight: 400; font-style: Regular; font-size: 14px; color:#A6A6A6; line-height: 100%; letter-spacing: -0.3px; margin-left: 10px; } } .stepBtn{ margin-right: 10px; margin-bottom: 3px; } } .stepMain{ width: 667px; margin: 0 auto; .title{ font-family: PingFang SC; font-weight: 400; font-style: Regular; font-size: 12px; color:#fff; letter-spacing: -0.3px; margin: 10px 0; } .addTxt{ &:deep(.el-input){ display: block; width: 667px; height: 80px !important; background-color: #363636 !important; border: none; border-radius: 8px; } } } } } } } .taskRight{ width: 339px; margin-left: 48px; } } } } } </style> 中console.log(partyUserInfo.value.avatar)的输出结果为https://cdn.shenyantuling.com/prod/image/head/shutiao1.png。 但是 报错显示:taskDetail.vue:98 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'avatar') at Proxy._sfc_render (taskDetail.vue:98:53) 即<img :src=partyUserInfo.avatar alt="">中找不到avatar
07-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值