React/TS表单中实现输入框标签双场景移位的CSS问题
React/TS表单标签移位问题解决:输入框有内容时的标签定位
问题背景
需要实现输入框标签在两种场景下移位:
- 输入框获得焦点时
- 输入框有内容(占位符未显示)时
目前焦点触发的移位已经通过.grid__item--fixedrowcolone实现,但输入框有内容时的场景始终无法生效。输入框与标签作为网格元素重叠放置且默认垂直居中,之前尝试了多种选择器变体都没成功,比如:
.grid__item--fixedrowcolone { &:not(~ .form__inputfield:placeholder-shown) { color: green; } }
相关代码
React表单组件代码
<div className={styles.form__inputwrapper} data-testid='form-input'> <div className={styles.form__inputsymbol} data-testid='form-input-icon'> <img src={lockSvg} alt='lock' width='24' height='24' /> </div> <div className={styles.grid__container} data-testid='form-input-field'> <div className={styles['grid__item--fixedrowcolone']}> <input className={styles.form__inputfield} type='text' pattern='^.*{8,}' id='pwd1' name='pwd1' value={inputValue} onChange={(e) => setInputValue(e.target.value)} placeholder=' ' required data-testid='forminput-input' /> </div> <div className={styles['grid__item--fixedrowcoltwo']}> <label className={styles.form__inputlabel} htmlFor='pwd1' data-testid='forminput-inputlabel' > wachtwoord <span className={styles.form__inputlabelvalmsg}> +312234 </span> </label> </div> </div> </div>
CSS Module SCSS代码
.grid { &__container { display: grid; justify-items: stretch; } &__item { &--fixedrowcolone, &--fixedrowcoltwo { display: flex; grid-column: 1; grid-row: 1; } } } .form { &__inputwrapper { display: flex; margin-bottom: 10px; position: relative; background: var(--theme_form_field_bg_color); border-radius: 4px; } &__inputsymbol { display: flex; align-self: center; padding-left: 10px; pointer-events: none; color: var(--theme_fg_color); font-size: 1.5em; transition: all 0.4s; filter: var(--theme_fg_color_filter) } &__inputfield { align-self: center; font-size: 1.5em; height: 50px; color: var(--theme_fg_color); background: none; outline: none; border: none; max-width: 280px; min-width: 250px; overflow: visible; touch-action: manipulation; } &__inputlabel { align-self: center; font-size: 1.5em; transition: .3s all ease; } &__inputlabelvalmsg { display: none; } } .grid__item--fixedrowcolone { &:focus-within ~ .grid__item--fixedrowcoltwo { top: 5px; font-size: .5em; align-self: start; } }
问题分析
之前的选择器错误在于:
.form__inputfield是.grid__item--fixedrowcolone的子元素,不是兄弟元素,所以~兄弟选择器完全不生效- 需要控制的目标是
.grid__item--fixedrowcoltwo里的标签,而不是.grid__item--fixedrowcolone本身
另外,输入框的placeholder=' '设置是对的——当输入内容后,占位符会隐藏,:placeholder-shown伪类会失效,这个逻辑没问题。
解决方案
利用CSS的:has()伪类(现代浏览器均支持),让.grid__item--fixedrowcolone根据子元素输入框的状态,控制兄弟元素.grid__item--fixedrowcoltwo的样式。同时需要给.grid__item--fixedrowcoltwo添加相对定位,确保top属性生效。
修改后的SCSS代码
首先给标签所在的网格项添加相对定位:
.grid__item--fixedrowcoltwo { position: relative; }
然后更新聚焦和内容触发的样式规则:
.grid__item--fixedrowcolone { // 输入框聚焦时移位 &:focus-within ~ .grid__item--fixedrowcoltwo, // 输入框有内容(占位符未显示)时移位 &:has(.form__inputfield:not(:placeholder-shown)) ~ .grid__item--fixedrowcoltwo { top: 5px; font-size: .5em; align-self: start; } }
效果验证
- 输入框聚焦时:标签正常移位
- 输入框输入内容后:即使失去焦点,标签也保持移位状态
- 清空输入框:标签回到默认垂直居中位置
内容的提问来源于stack exchange,提问作者pcvnes
相关产品推荐
相关产品推荐

