CSS on :focus within child of contenteditable

CSS on :focus within child of contenteditable

我正在尝试检测 contenteditable 元素的子元素上的 focus,以实现纯粹的 CSS 样式。 (我知道我可以用 JS 检测到这个,添加一个额外的 class 然后那样做,但那太啰嗦了。)

基本上,我有一些类似的东西:

<div contenteditable="true">
  Some text <span class="edit">that</span> goes here.
</div>

我尝试了 CSS 的思路:

.edit:focus {
  color: #FF0000;
}

我希望 span 在插入符号进入时改变颜色,但显然焦点仅应用于设置为 contenteditablediv,而不是其任何子项。我已经尝试将第二个 contenteditable 应用于 span,但除了是一种非常草率的方法之外,它无论如何都不起作用。

有解决办法吗?

只需添加这个而不是 :focus。 Fiddle.

.edit {
  color: #f00;
}

我的理解是可以(自动)获得焦点的元素类型是有限的。

SO Question

一个选项是将 tabindex 添加到跨度。

body {
  font-size: 3rem;
}
div[contenteditable=true] .edit:focus {
  color: #FF0000;
}
<div contenteditable="true">Some text <span class="edit" tabindex="0">that</span> goes here.</div>

:focus > .edit { color: #cc0000; }

<div contenteditable="true">Some text <span class="edit">that</span> goes here.</div>
<div contenteditable="true">Some text that goes here.</div>

由于 contenteditable 元素中的元素通常无法获得焦点的限制,我建议在选择时通过向 <span> 元素添加 class 来伪装它包含在其中,您可以通过监视选择的更改来做到这一点(您必须使用鼠标和键盘事件并轮询 Firefox until the selectionchange event is implemented in that browser 中的完整性)。

var selectionContainer = null;

function updateSelectionContainer() {
  var newSelectionContainer = null;
  var sel;
  if (window.getSelection && (sel = window.getSelection()).rangeCount) {
    newSelectionContainer = sel.getRangeAt(0).commonAncestorContainer;

    // Ensure we have an element rather than a text node
    if (newSelectionContainer.nodeType != 1) {
      newSelectionContainer = newSelectionContainer.parentNode;
    }
  }
  if (newSelectionContainer != selectionContainer) {
    if (selectionContainer) {
      selectionContainer.className = selectionContainer.className.replace(/ ?containsSelection/, "");
    }
    if (newSelectionContainer) {
      newSelectionContainer.className +=
        (newSelectionContainer.className ? " containsSelection" : "containsSelection");
    }
    selectionContainer = newSelectionContainer;
  }
}

if ("onselectionchange" in document) {
  document.onselectionchange = updateSelectionContainer;
} else {
  var el = document.getElementById("editor");
  el.onmousedown = el.onmouseup = el.onkeydown = el.onkeyup = el.oninput = updateSelectionContainer;
  window.setInterval(updateSelectionContainer, 100);
}
div {
  font-size: 200%;
}

.edit.containsSelection {
  color: red;
  font-weight: bold;
}
<div contenteditable="true" id="editor">
  Some text <span class="edit">that</span> goes here.
</div>