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

Selecting an element based on the presence of surrounding sibling elements

我有以下 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>,则它的 border-radius 从左上角到左下角将为零。

我使用了:

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

但是,当 <input> 之后有一个 <span> 时,输入边框半径应该仅从右上角和右下角开始为零。显然我不能为这个选择器使用 + 选择器。

<span><input> 之后而不使用 JavaScript 和改变 HTML 时,我怎样才能达到预期的结果?

更新:

按照下面的答案,尤其是 BoltClock♦ 方法 - 看来问题差不多解决了!下图演示了所有不同的场景以及用于应用它们的代码。

唯一尚未起作用的情况是输入之前只有一个跨度。

当前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>

I can simply give the main container a class accordingly, but I want to see if there is a way to do it without the need to alter the HTML.

不,没有 select 或者 select 以前的兄弟姐妹 (Is there a previous sibling selector?)

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

在你的特殊情况下(如果你的 HTML 与你给定的例子相比没有太大变化)你可以使用这样的东西:

尝试删除/注释掉第一个跨度并查看差异。它会简单地将 border-radius: 0 应用于所有输入元素,但前一个元素是 span

的元素除外

//编辑

您现在可以直接看到差异,无需注释掉

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

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

JSFiddle

通常,无论 HTML 结构如何,您都不能将作为另一个元素的前一个兄弟元素的元素作为目标,因为 there is no previous sibling selector.

但是,鉴于您的结构,仍有许多可能的情况可以使用您当前可用的内容来解决。如果 <input> 的任一侧或两侧最多只有一个 <span>,并且此 <div> 元素内没有其他 <span> 元素,您将能够在所有这些情况下以 <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> 元素仅出现在 <input> 之后 时,如果这导致 <input> 成为第一个子元素它的父级 <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>时,可以在第一个<span>上使用:not(:only-of-type)使用相邻的兄弟选择器以防止在这种情况下匹配第一个 <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;
}

作为奖励,由于您正在处理 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,以防止选择器在两边都存在 <span> 元素时匹配。