根据周围兄弟元素的存在选择元素

时间:2015-04-01 12:54:27

标签: html css css-selectors

我有以下HTML结构。

<div class="fieldset">
    <p>Normal Input<i class="icon-question tooltip-top" title="Text Goes Here"></i></p>
    <div>
        <span><i class="icon-cart"></i></span>
        <input name="">
        <span><i class="icon-cart"></i></span>
        <i class="icon-question tooltip-top" title="Text Goes Here"></i>
    </div>
</div>

我正在尝试根据<input>所处的位置更改border-radius的设置。

例如,如果<input>之前有<span>,则其边框半径将从左上角和左下角为零。

我这样做是通过使用:

.fieldset > div > span + input {
    border-radius: 0 4px 4px 0;
}

但是,如果在<span>之后存在<input>,则输入边界半径应仅从右上方和下方开始为零。显然,我无法使用+选择器。

如果<span><input>之后不使用JavaScript并更改HTML,我如何才能获得所需的结果?

更新

按照下面的答案,特别是BoltClock♦方法 - 似乎问题几乎已经解决了!下图显示了所有不同的场景以及用于应用它们的代码。

enter image description here 唯一尚未运行的情况是输入前只有一个跨度。

目前的CSS是:

/*Fieldsets*/
.fieldset {
    width: 100%;
    display: table;
  position: relative;
  white-space: nowrap;
  margin-bottom: 15px;
}

.fieldset:last-of-type {
    margin-bottom: 0;
}

        /*Fieldsets > Labels*/
        .fieldset > p { 
            width: 1%;
            margin-bottom: 3px;
        }  

        /*Fieldsets > Input Container*/
        .fieldset > div {
            display: table-row;
            position: relative;
        }  

            .fieldset > div > * {
                display: table-cell;
              white-space: nowrap;
              vertical-align: middle;
                position: relative;
            }  

            /*Fieldsets > Input + Icon*/
            .fieldset > div > span {
                border: 1px solid #B0C2CE;
                padding: 5px 15px;
                font-weight: bold;
                width: 1%;
            }  

            /*Fieldsets > Input + Icon Senarios*/
            .fieldset > div > span:first-of-type {
                border-right: 0;
                border-radius: 4px 0 0 4px;
            } 

            .fieldset > div > span:last-of-type {
                border-left: 0;
                border-radius: 0 4px 4px 0;
            }  

            .fieldset > div > span:not(:only-of-type) + input {
                border-radius: 0;
            }

            .fieldset > div > span + input,
            .fieldset > div > span + textarea,
            .fieldset > div > span + select,
            .fieldset > div > span + .select-dropdown-single .select-dropdown-input,
            .fieldset > div > span + .select-dropdown-multi .select-input {
                border-radius: 0 4px 4px 0;
            }

            /*Fieldsets > Input + Help toolTip icon*/
            .fieldset > div [class^="tooltip-"],
            .fieldset > div [class*=" tooltip-"] {
                text-align: center;
                width: 30px;
            } 

HTML:

<div class="fieldset">
                <p>Normal Input</i></p>
                <div>
                    <input name="">
                </div>
            </div>

            <div class="fieldset">
                <p>Normal Input</p>
                <div>
                    <span><i class="icon-cart"></i></span>
                    <input name="">
                </div>
            </div>

            <div class="fieldset">
                <p>Normal Input</p>
                <div>
                    <span><i class="icon-cart"></i></span>
                    <input name="">
                    <span><i class="icon-cart"></i></span>
                </div>
            </div>

            <div class="fieldset">
                <p>Normal Input</p>
                <div>
                    <span><i class="icon-cart"></i></span>
                    <input name="">
                    <span><i class="icon-cart"></i></span>
                    <i class="icon-question tooltip-top" title="Text Goes Here"></i>
                </div>
            </div>

3 个答案:

答案 0 :(得分:3)

通常,无论HTML结构如何,都无法定位作为另一个元素的前一个兄弟的元素,因为there is no previous sibling selector

但是,根据您的结构,有许多可能的情况仍然可以使用当前可用的内容进行说明。如果<span>或双方的任意一侧只有一个<input>,并且此<span>元素中没有其他<div>个元素,那么您将能够在所有这些情况下定位<input>

正如问题所示,如果<span>元素仅在<input> 之前出现,请使用相邻的兄弟选择器定位<input>

<div class="fieldset">
    <p>Normal Input<i class="icon-question tooltip-top" title="Text Goes Here"></i></p>
    <div>
        <span><i class="icon-cart"></i></span>
        <input name="">
        <i class="icon-question tooltip-top" title="Text Goes Here"></i>
    </div>
</div>
.fieldset > div > span + input {
    border-radius: 0 4px 4px 0;
}

如果<span>元素仅在<{strong> <input>之后出现,那么如果这导致<input>成为其父{{1}的第一个孩子你可以使用<div>仅在这种情况下定位:first-child

<input>
<div class="fieldset">
    <p>Normal Input<i class="icon-question tooltip-top" title="Text Goes Here"></i></p>
    <div>
        <input name="">
        <span><i class="icon-cart"></i></span>
        <i class="icon-question tooltip-top" title="Text Goes Here"></i>
    </div>
</div>

.fieldset > div > input:first-child { border-radius: 4px 0 0 4px; } 元素在<span>之前和之后出现时,您可以在第一个<input>上使用:not(:only-of-type)与相邻的兄弟选择器防止在这种情况下匹配第一个<span>

<span>
<div class="fieldset">
    <p>Normal Input<i class="icon-question tooltip-top" title="Text Goes Here"></i></p>
    <div>
        <span><i class="icon-cart"></i></span>
        <input name="">
        <span><i class="icon-cart"></i></span>
        <i class="icon-question tooltip-top" title="Text Goes Here"></i>
    </div>
</div>

作为奖励,因为您正在处理.fieldset > div > span:not(:only-of-type) + input { border-radius: 0; } 属性,请记住,您可以有选择地使用其longhands以避免必须处理第三种情况(border-radius双方):

<span>

请注意,在这种情况下使用.fieldset > div > input { border-radius: 4px; } .fieldset > div > span:only-of-type + input { border-top-left-radius: 0; border-bottom-left-radius: 0; } .fieldset > div > input:first-child { border-top-right-radius: 0; border-bottom-right-radius: 0; } ,以防止选择器匹配,如果双方都存在:only-of-type元素。

答案 1 :(得分:1)

  

我可以简单地给主容器一个类,但是我想知道是否有办法在不需要改变HTML的情况下完成它。

不,没有选择器选择上一个兄弟(Is there a previous sibling selector?

下一个CSS版本中只有一个草稿:http://dev.w3.org/csswg/selectors-4/#general-sibling-combinators

答案 2 :(得分:0)

在你的特殊情况下(如果你的HTML没有从你给出的例子中改变很多)你可以使用这样的东西:

尝试删除/评论第一个范围并查看差异。它只会将border-radius: 0应用于所有输入元素,但前一个元素为span

的元素除外

//编辑

您现在可以直接看到差异,无需发表评论

.fieldset > div > input {
    border-radius: 0;
}

.fieldset > div > span + input {
    border-radius: 0 4px 4px 0 !important;
}

JSFiddle