Курсор в contenteditable не ведет себя должным образом в Chrome
У меня есть проблема, когда курсор переходит в неправильное место, когда пользователь нажимает внутри contenteditable div
но за пределами фактического текста. Кажется, это проблема только в более новых версиях Chrome (а также Opera): по совпадению я протестировал мой пример в более старом браузере (Chrome версии 55), и проблема вообще отсутствовала. Нет проблем в Edge/IE11/FireFox либо.
Эта проблема возникает только тогда, когда пользователь нажимает за строкой текста или на пустой строке, которая находится между двумя желтыми divs
с классом pagebreak
, Курсор оказывается выше первого pagebreak
div
, И имеет ли это прямое отношение, я не знаю, но проблема исчезает, когда 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>
Проблема в текстовом поле слева, справа - как и ожидалось, .flowbox
div
был удален.
Изменить 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 (редактор содержимого справа) и список всех классов, равных по сравнению с моим кодом (редактор содержимого слева).
div.textframe
................section.editor
p.textOutline
................article.content
span.flowbox.spacer
......mark.vertRule
span.pagebreak.spacer
..mark.breaker
Есть 2 требования, которые касаются ФП:
Когда пустые области вокруг
<span>s
при щелчке курсор переместится в угол области содержимого.Количество символов в строке должно соответствовать текущей емкости кода 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
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>