Курсор в contenteditable не ведет себя должным образом в Chrome

У меня есть проблема, когда курсор переходит в неправильное место, когда пользователь нажимает внутри contenteditable div но за пределами фактического текста. Кажется, это проблема только в более новых версиях Chrome (а также Opera): по совпадению я протестировал мой пример в более старом браузере (Chrome версии 55), и проблема вообще отсутствовала. Нет проблем в Edge/IE11/FireFox либо.

Эта проблема возникает только тогда, когда пользователь нажимает за строкой текста или на пустой строке, которая находится между двумя желтыми divs с классом pagebreak, Курсор оказывается выше первого pagebreakdiv, И имеет ли это прямое отношение, я не знаю, но проблема исчезает, когда div с классом flowbox устранен. К сожалению я не могу удалить это div с классом flowbox из приложения.

Я собрал пример, показывающий мою проблему в этой скрипке: https://jsfiddle.net/dymcn1ao/

<div class="textframe a">
    <div class="flowbox"></div>
    <article contenteditable="true">
        <p>
            <span>
                <span>Foo bar baz</span>
                <br>
                <span class="pagebreak" contenteditable="false" style="min-height: 80px"></span>
                <span>Foo bar baz</span>
                <br>
                <span>Lorem ipsum dolor sit amet, consectetur adi piscing elit.</span>
                <br>
                <br>
                <span class="pagebreak" contenteditable="false" style="min-height: 80px"></span>
                <br>
                <span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
            </span>
        </p>
    </article>
</div>

Проблема в текстовом поле слева, справа - как и ожидалось, .flowboxdiv был удален.

Изменить 1:

Я создал новый пример, который, возможно, легче понять. Другие элементы в .textframe (подобно элементам pagebreak и flowbox) действительно имеют конкретные цели, поэтому их нельзя игнорировать. Вот ссылка на улучшенную демонстрацию: https://jsfiddle.net/q4pu37dn/15/

5 ответов

Решение

Обновление 3 (демо 3)


введите описание изображения здесь

изменения

Я заметил, что больше нет position: relative используется в большинстве текущих OP-кодов, что хорошо, но я считаю, что это было забыто:

<span class='pagebreak spacer' contenteditable = "ложь" ></span>

Я считаю, что вы изначально использовали contenteditable="false" для того, чтобы дать .pagebreak s дополнительная функциональность и предотвращает их удаление, поэтому я добавил их обратно.


сравнение

Демонстрация 3 содержит мое решение рядом с OP-кодом для сравнения поведения. Демонстрация 3 также имеет 2 кнопки (по 1 для каждого редактора контента), которые выделяют каждую <span> текста. Ниже приведен список классов из кода OP (редактор содержимого справа) и список всех классов, равных по сравнению с моим кодом (редактор содержимого слева).

  1. div.textframe................ section.editor
  2. p.textOutline................ article.content
  3. span.flowbox.spacer...... mark.vertRule
  4. span.pagebreak.spacer.. mark.breaker

Есть 2 требования, которые касаются ФП:

  1. Когда пустые области вокруг <span>s при щелчке курсор переместится в угол области содержимого.

  2. Количество символов в строке должно соответствовать текущей емкости кода OP.

Эта проблема существовала годами, но причиной ее возникновения является туманность, поэтому, если вы относитесь к этому аберрации как к простому поведению, вы можете просто противостоять ему, прививая другое поведение.

Demo2 и Demo3 отвечают этим требованиям, просто применяя следующие наборы стилей:

Демо 2

article p {display: table;...

Демо 3

.content {display:table-cell;...

Поведение ячеек таблиц жесткое и хорошо разработанное, и AFAIK - единственный незаменяемый элемент, который по умолчанию соответствует его содержимому и соответствует окружающим элементам таблицы. В качестве бонуса элемент с display: table-cell (не <td>) не обязательно быть вложенным в <tr> это в пределах <table>,


Демо 3

.content { display: table-cell;...

скрипка

/* Begin Defaults */

* {
  margin: 0;
  padding: 0;
  border: 0;
  box-sizing: border-box;
}

html,
body {
  background: white;
  font: 400 16px/1.45 Arial;
  height: 100%;
  width: 100%;
}

/* End Defaults */

/* Begin Optionak Layout */

#page01 {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-evenly;
  align-items: flex-start;
  background: rgba(45, 99, 198, 0.6);
  margin: 0 auto 20px;
  height: fit-content;
  min-width: 100%
}

/* End Optional Layout */

/* Begin Primary Styles */

.editor {
  width: 350px;
  height: 600px;
  border: 1px solid black;
  background: #fff;
}

.vertRule {
  float: right;
  clear: right;
  width: 30px;
  height: 600px;
}

.content {
  display: table-cell;
  word-break: break-word;
}

mark {
  display: block;
  pointer-events: none;
}

.break {
  min-height: 80px;
}

/* End Primary Styles */

/* Begin Control */

/* https://jsfiddle.net/q4pu37dn/15 */

.textframe {
  width: 350px;
  height: 600px;
  border: 1px solid black;
  background: #fff;
}

.flowbox {
  float: right;
  clear: right;
  width: 30px;
  height: 600px;
}

.spacer {
  background: yellow;
}

.pagebreak {
  display: block;
  min-height: 80px;
}

/* End Control */

/* Begin Demo Test */

.btn {
  display: inline-block;
  font: inherit;
  margin: 5px 10px;
  padding: 2px 5px;
  border: 5px outset grey;
  border-radius: 8px;
  color: #000;
  cursor: pointer;
}

[type='checkbox']:checked+label {
  background: rgba(255, 12, 34, 0.75);
  border: 5px inset grey;
  color: #fff;
}

#outline1:checked+label+#outline2+label+hr+#page01>.editor>.content *,
#outline2:checked+label+hr+#page01>.textframe>#textOutline *:not(.spacer) {
  color: #fff;
  background: tomato;
  outline: 2px solid red;
}

#outline1:checked+label+#outline2+label+hr+#page01>.editor>.content>.break,
#outline2:checked+label+hr+#page01>.textframe>#textOutline>.spacer {
  background: yellow;
  outline: none;
}

/* End Demo Test */
<!-- Begin Demo Test -->

<input id="outline1" type='checkbox' hidden>
<label for='outline1' class='btn'>Outline 1</label>

<input id="outline2" type='checkbox' hidden>
<label for='outline2' class='btn'>Outline 2</label>

<hr>

<!-- End Demo Test -->

<!-- Begin Optional Layout Part 1 -->

<main id='page01'>

  <!-- End Optional Layout Part 1 -->

  <!-- Begin Primary Markup -->

  <section class="editor" contenteditable='true'>
    <mark class="vertRule" contenteditable='false'></mark>
    <article class='content'>
      <span>
      Clicking here is not a problem
    </span>
      <br>
      <br>
      <span>
      Lorem ipsum
    </span>
      <mark class="break" contenteditable='false'></mark>
      <span>
      Clicking here (on empty space, not directly on text) will put the caret above the first .break element.
    </span>
      <br>
      <br>
      <span>
      Lorem ipsum
    </span>
      <mark class="break" contenteditable='false'></mark>
      <br>
      <span>
      Clicking here is not a problem
    </span>
      <br>
      <br>
    </article>
  </section>

  <!-- End Primary Markup -->

  <!-- Begin Control -->

  <div class="textframe" contenteditable>

    <p id='textOutline'>

      <span class="spacer flowbox"></span>
      <span>
      Clicking here is not a problem
    </span>
      <br>
      <br>
      <span>
      Lorem ipsum
    </span>
      <span class="spacer pagebreak"></span>
      <span>
      Clicking here (on empty space, not directly on text) will put the caret above the first .pagebreak element.
    </span>
      <br>
      <br>
      <span>
      Lorem ipsum
    </span>
      <span class="spacer pagebreak"></span>
      <br>
      <span>
      Clicking here is not a problem
    </span>
      <br>
      <br>
    </p>
  </div>

  <!-- End Control -->

  <!-- Begin Optional Layout Part 2 -->

</main>

<!-- End Optional Layout Part 2 -->


Обновление 2 (Демо 2)


ОП в отношении Демо 1:

"Вы решили это для моего надуманного примера, да. К сожалению, невозможно установить эти значения для элементов в реальном приложении, поток полностью выходит из строя".

Смотрите Demo 2, он работает лучше, чем Demo 1. Поскольку он использует только позиционированные элементы, в потоке нет конфликтов. Чтобы адаптировать Demo 2 к вашему приложению, все что вам нужно сделать, это добавить position:relative к родительским элементам. Соответствующий стиль выглядит следующим образом:

article p {display: table;...

Было необходимо назначить position:relative ко всему вложенному в .textframe в противном случае static элементы не будут взаимодействовать с позиционированными элементами. Существуют правила, которым придерживаются таблицы и их компоненты, которые применяются не только к его содержимому, но и к тому, как они взаимодействуют со своими соседними элементами.


Демо 2

article p {display: table...

.container {
  width: 400px;
  float: left
}

.textframe {
  width: 350px;
  height: 650px;
  outline: 2px dotted lightblue;
  overflow: hidden;
  margin: 0 15px 0 0;
  /* Needed for long words */
  word-break: break-word;
}

.textframe article {
  position: relative;
  height: 650px; 
}

article p {
  display: table;
  margin: 0;
  position:relative;
}

.flowbox {
  width: 2px;
  height: 650px;
  float: right;
  clear: right;
  outline: 1px solid red;
}

.pagebreak {
  display: block;
  pointer-events:none;
  position:relative;
}
<div class="container">
      <h4>
       article p {display: table; position: relative;}<br>
       all children of .textframe have: position: relative;  
      </h4>
      <div class="textframe a">
        <div class="flowbox"></div>
        <article contenteditable="true">
           <p>
            <span>
              <span>Foo bar baz</span>
            <br>
            <mark class="pagebreak" contenteditable="false" style="min-height: 80px"></mark>
            <span>Foo bar baz</span>
            <br>
            <span>Lorem ipsum dolor sit amet, consectetur adi piscing elit.</span>
            <br>
            <br>
            <mark class="pagebreak" contenteditable="false" style="min-height: 80px"></mark>
            <br>
            <span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
            </span>
          </p>
          <hr>
        </article>
      </div>
    </div>


Refences

MDN - Поплавок

MDN - Должность

CSS Tricks - абсолютное позиционирование внутри относительного позиционирования

CSS Tricks - все о плаваниях

дисплей: таблица / таблица-ячейка

слово-брейк: Распад слово


Эта проблема возникает потому, что вы используете float: right;,

Не используйте свойство CSS float: right; если тебе это не нужно. У вас может быть много проблем с этим. В твоем случае тебе это не нужно. Вместо этого вы используете inline-block элементы как <div class="flowbox"> а также <article contenteditable="true">,

Минимальный пример с float:right (С проблемой)

.textframe {
    width: 311px;
    height: 650px;
    outline: 2px dotted lightblue;
    overflow: hidden;
    margin: 0 15px 0 0;
}
.flowbox {
    width: 2px;
    height: 650px;
    float: right;
    clear: right;
    outline: 1px solid red;
}
.pagebreak {
    display: block;
    position: relative;
    background: yellow;
}
<div class="container">
  <h4>
    With problem:
  </h4>
  <div class="textframe a">
    <div class="flowbox"></div>
    <article contenteditable="true">
      <p>
        <span>
          <span>Foo bar baz</span>
          <br>
          <span class="pagebreak" contenteditable="false" style="min-height: 80px"></span>
          <span>Foo bar baz</span><br>
          <span>Lorem ipsum CLICK ABOVE THIS WORDS sit amet, consectetur adi piscing elit.</span>
          <br>
          <br>
          <span class="pagebreak" contenteditable="false" style="min-height: 80px"></span>
          <br>
          <span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
        </span>
      </p>
    </article>
  </div>
</div>

Решение

Минимальный пример с display:inline-block (без проблем)

Примечание: теперь я разместил ваш <div class="flowbox"></div> после <article> элемент.

.textframe {
    width: 311px;
    height: 650px;
    outline: 2px dotted lightblue;
    overflow: hidden;
    margin: 0 15px 0 0;
}
.flowbox {
    width: 2px;
    height: 650px;
    outline: 1px solid red;
}
.pagebreak {
    display: block;
    position: relative;
    background: yellow;
}
.flowbox, article{display:inline-block;vertical-align:top;}
article{width: 305px;}
<div class="container">
  <h4>
    With problem:
  </h4>
  <div class="textframe a">
    <article contenteditable="true">
      <p>
        <span>
          <span>Foo bar baz</span>
          <br>
          <span class="pagebreak" contenteditable="false" style="min-height: 80px"></span>
          <span>Foo bar baz</span><br>
          <span>Lorem ipsum CLICK ABOVE THIS WORDS sit amet, consectetur adi piscing elit.</span>
          <br>
          <br>
          <span class="pagebreak" contenteditable="false" style="min-height: 80px"></span>
          <br>
          <span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
        </span>
      </p>
    </article>
    <div class="flowbox"></div>
  </div>
</div>

Проблема с дисплеем, я тоже новичок в этом, но когда я изменил ваш диапазон на div, он работал нормально, дайте мне знать, если это правильно, или я не смог правильно понять ваш вопрос.

Сейчас я не уверен, почему это произошло, поэтому не могу дать вам подробное объяснение.

Примечание. Использование span и div не будет правильным после этого, поэтому придется изменить на div и в других местах.

.title {
  left: 20px;
}
.container {
  float: left;
  width: 400px;
}
.textframe {
  width: 311px;
  height: 650px;
  outline: 2px dotted lightblue;
  overflow: hidden;
  margin: 0 15px 0 0;
}
.textframe.b {
  left: 380px;
}
.textframe article {
  position: relative;
  height: 650px;
}
article p {
  margin: 0;
}
.pagebreak {
  display: block;
  position: relative;
  background: yellow;
}
.flowbox {
  width: 2px;
  height: 650px;
  float: right;
  clear: right;
  outline: 1px solid red;
}
<div class="container">
  <h4>
    With problem:
  </h4>
  <div class="textframe a">
    <div class="flowbox"></div>
    <article contenteditable="true">
      <p>
        <span>
          <span>Foo bar baz</span>
          <br>
          <span class="pagebreak" contenteditable="false" style="min-height: 80px"></span>
          <div>Foo bar baz</div>
          <br>
          <div>Lorem ipsum dolor sit amet, consectetur adi piscing elit.</div>
          <br>
          <br>
          <span class="pagebreak" contenteditable="false" style="min-height: 80px"></span>
          <br>
          <span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
        </span>
      </p>
    </article>
  </div>
</div>
<div class="container">
  <h4>
    Without problem:
  </h4>
  <div class="textframe b">
    <article contenteditable="true">
      <p>
        <span>
          <span>Foo bar baz</span>
          <br>
          <span class="pagebreak" contenteditable="false" style="min-height: 80px"></span>
          <div>Foo bar baz</div>
          <br>
          <div>Lorem ipsum dolor sit amet, consectetur adi piscing elit.</div>
          <br>
          <br>
          <span class="pagebreak" contenteditable="false" style="min-height: 80px"></span>
          <br>
          <span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
        </span>
      </p>
    </article>
  </div>
</div>

Я использую новейшую версию Chrome для Linux/Ubuntu, и это, похоже, решило проблему. Я только что удалил contenteditable из статьи и поместил ее в промежутки, которые вы хотели редактировать.

<article>
      <p>
        <span>
          <span contenteditable="true">Foo bar baz</span>
          <br>
          <span class="pagebreak" contenteditable="false" style="min-height: 80px"></span>
          <span contenteditable="true">Foo bar baz</span>
          <br>
          <span contenteditable="true">Lorem ipsum dolor sit amet, consectetur adi piscing elit.</span>
          <br>
          <br>
          <span class="pagebreak" contenteditable="false" style="min-height: 80px"></span>
          <br>
          <span contenteditable="true">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
        </span>
      </p>
    </article>

Я думаю, что проблема с span, если у вас есть пустой span в нем. Я прошел через эту проблему, работая с contenteditable, поэтому курсор появляется там, но вы не можете заставить его двигаться.

Я предложу вам удалить промежуток от вашего p к каждому абзацу, так что если span пуст, попробуйте удалить его на Backspace/ Delete.

Или обратитесь к CKEDITOR, чтобы решить эту проблему

article p, article div
{
    line-height: 1.25;
    margin-top: 12px;
    margin-bottom: 12px; /*  margin-bottom: 10px; removed for proper pagebreak 31-1-2017*/
    font-family: Helvetica;
}

.title {
  left: 20px;
}
.container {
  float: left;
  width: 400px;
}
.textframe {
  width: 311px;
  height: 650px;
  outline: 2px dotted lightblue;
  overflow: hidden;
  margin: 0 15px 0 0;
}
.textframe.b {
  left: 380px;
}
.textframe article {
  position: relative;
  height: 650px;
}
article p {
  margin: 0;
}
.pagebreak {
  display: block;
  position: relative;
  background: yellow;
}
.flowbox {
  width: 2px;
  height: 650px;
  float: right;
  clear: right;
  outline: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <h4>
    With problem:
  </h4>
  <div class="textframe a">
    <div class="flowbox"></div>
    <article contenteditable="true">
      <p>
        <span>
          <span>Foo bar baz</span>
          <br>
          <span class="pagebreak" contenteditable="false" style="min-height: 80px"></span>
          <span>Foo bar baz</span>
          <br>
          <span>Lorem ipsum dolor sit amet, consectetur adi piscing elit.</span>
          <br>
          <br>
          <span class="pagebreak" contenteditable="false" style="min-height: 80px"></span>
          <br>
          <span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
        </span>
      </p>
    </article>
  </div>
</div>
<div class="container">
  <h4>
    Without problem:
  </h4>
  <div class="textframe b">
    <article contenteditable="true">
      <p>
        <span>
          <span>Foo bar baz</span>
          <br>
          <span class="pagebreak" contenteditable="false" style="min-height: 80px"></span>
          <span>Foo bar baz</span>
          <br>
          <span>Lorem ipsum dolor sit amet, consectetur adi piscing elit.</span>
          <br>
          <br>
          <span class="pagebreak" contenteditable="false" style="min-height: 80px"></span>
          <br>
          <span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
        </span>
      </p>
    </article>
  </div>
</div>

Другие вопросы по тегам