9 апреля 2013 в 13:36

Кроссворд из регулярных выражений: интерактивная версия

Вдохновлённый недавним постом и комментарием к нему, решил сделать аналогичную интерактивную версию.
Есть навигация с клавиатуры, подсветка активных строк, а также индикация соответствия строки регулярному выражению. Для удобства подсказки выделенной ячейки поворачиваются горизонтально.
Разметка – чистый HTML+CSS3.
Почти работает в последних версиях популярных браузеров. В IE9 глючит навигация мышкой, в FF и Opera наблюдаются проблемы с производительностью. И только Chrome – 100% OK.
Буду благодарен за советы по оптимизации.
Ссылка – вот. Детали реализации – под катом.
image

Реализация

Пожалуй, самое интересное в реализации – это сетка кроссворда. Ячейка сверстана с помощью развития идеи «честных полигонов». Если коротко – создаются несколько контейнеров с visibility:hidden и overflow:hidden, что предоставляет отсекание лишнего содержимого. Внутри создаётся содержимое с visibility:visible. Использование этого вместе с вращением у контейнеров позволяет задать конечному элементу форму практически любого выпуклого многоугольника.
Чтобы сделать этот многоугольник с границами в несколько пикселей, к содержимому были добавлены дополнительные внешние контейнеры с аналогичными поворотами и нужными границами. Суть показана на картинке. Здесь красным пунктиром обозначены внешние «невидимые контейнеры», чёрным – внутренние контейнеры с границами.

Сначала идут 3 вложенных друг в друга элемента с красной рамкой, внутри них – так же вложенные видимые контейнеры с чёрной рамкой.
Код
HTML
<span class="hexcell">
	<span>
		<span>
			<span>
				<span>
					<span class="input"></span>
				</span>
			</span>
		</span>
	</span>
</span>

CSS
.hexcell {
	display: inline-block;
	vertical-align: middle;
	text-align: center;
	width: 50px;
	height: 70px;
	overflow:hidden;
	visibility:hidden;
	-webkit-transform: rotate(120deg);
	   -moz-transform: rotate(120deg);
	    -ms-transform: rotate(120deg);
	     -o-transform: rotate(120deg);
	        transform: rotate(120deg);
}
.hexcell span {
	position:relative;
	width:100%;
	height:100%;
	display:inline-block;
	overflow:hidden;
	visibility:hidden;
	vertical-align: middle;
	text-align: center;
}
.hexcell > span {
	-webkit-transform: rotate(-60deg);
	   -moz-transform: rotate(-60deg);
	    -ms-transform: rotate(-60deg);
	     -o-transform: rotate(-60deg);
	        transform: rotate(-60deg);
}
.hexcell > span > span {
	-webkit-transform: rotate(-60deg);
	   -moz-transform: rotate(-60deg);
	    -ms-transform: rotate(-60deg);
	     -o-transform: rotate(-60deg);
	        transform: rotate(-60deg);
}
.hexcell > span > span > span{	/*первая рамка*/
	border: 1px solid #000000;
	height:68px;
	width:48px;
	visibility:visible;
	-webkit-transform: rotate(120deg);
	   -moz-transform: rotate(120deg);
	    -ms-transform: rotate(120deg);
	     -o-transform: rotate(120deg);
	        transform: rotate(120deg);
}
.hexcell > span > span > span > span{	/*вторая рамка*/
	border: 1px solid #000000;
	height:68px;
	width:48px;
	top:-1px;
	left:-1px;
	visibility:visible;
	-webkit-transform: rotate(-60deg);
	   -moz-transform: rotate(-60deg);
	    -ms-transform: rotate(-60deg);
	     -o-transform: rotate(-60deg);
	        transform: rotate(-60deg);
}
.hexcell > span > span > span > span > span.input{	/*содержимое с третьей рамкой*/
	border: 1px solid #000000;
	height:68px;
	width:48px;
	top:-1px;
	left:-1px;
	position:relative;
	visibility:visible;
	font-size:34px;
	-webkit-transform: rotate(-60deg);
	   -moz-transform: rotate(-60deg);
	    -ms-transform: rotate(-60deg);
	     -o-transform: rotate(-60deg);
	        transform: rotate(-60deg);
}
Для корректного объединения ячеек в сетку делается следующее:
  • ячейки оборачиваются в контейнер, содержимое которого выравнивается по центру
  • используется псевдо-border-collapse: всем ячейкам, кроме последней, ставится меньшая ширина и последнего элемента (контейнер содержимого) убирается правая граница
  • для совмещения строчек добавляется отрицательный margin-top
В такой комбинации несколько поставленных рядом ячеек с нужными стилями выстраиваются в нормальную сетку.
Для расстановки заголовков средствами CSS они добавляются перед соответствующей ячейкой в контейнер с абсолютной позицией и выравниванием по правому краю. Таким образом, пропадает привязка к размеру строки и достаточно правильно расположить контейнер через CSS transform.
Всё остальное не представляет из себя ничего сверхъестественного, потому не буду это описывать в посте. Желающие смогут всё найти в исходниках.

Работоспособность

Отдельные вопросы вызывает функционирование. Кроссворд гарантированно функционирует только под Webkit (разработка велась под Chrome последней версии). В Firefox и Opera тоже работает, но почему-то с заметными тормозами, особенно в Opera. Как показал профайлер в той же Opera, больше всего времени уходит на перерисовку, даже с отключёнными transitions. Под IE10 не тестировалось.
UPD. В IE10 работает отлично, спасибо alexxxst.
Под 9-м был баг с позиционированием заголовков (горизонтальные съезжали влево). Как я понял, это какая-то его специфика. Первый элемент в строке с position:absolute съезжает к левому краю, несмотря на отсутствие явного указания положения. Исправлено через display:inline-block у контейнера строки.
Также вместе с поворотами криво рендерится текст. В целом, как показал опыт, рендеринг графики вместе с transform пока оставляет желать лучшего.
UPD2. Исходники
Виталий Онищенко @UZER2006
карма
28,0
рейтинг 0,0
Самое читаемое Разработка

Комментарии (41)

  • +5
    Даже немного жаль, что уже решил его.
    Предложение: можно добавить вращение кроссворда мышкой или стрелками.
    • 0
      Идея интересна, но сложновата в реализации.
      Не думаю, что это столь необходимо. А ещё боюсь, что тогда это всё даже в Webkit начнёт тормозить.)
      • 0
        Кверху тормашками читать это всё сложно. Я когда решал, распечатал и много его крутил. Очень удобно.
  • +2
    «Честные полигоны» понравились, интересная реализация.

    p.s. странно, но в Firefox при манипуляциях на странице кушается раза в полтора больше ресурсов, чем в Хроме.
    • 0
      Да, о производительности я писал. Я подозреваю (но не уверен), что во всём виноваты transforms. Почему-то Webkit и IE с ними лучше справляется.
  • 0
    Не стоило текст поворачивать более чем на 90 градусов, читать не удобно
    • 0
      К сожалению, хорошего решения по поводу удобного восприятия текста так и не нашёл. Направление текста указывает направление слова в сетке.
      • 0
        Верхние и нижние подписи можно на 180 градусов развернуть, тогда они будут читаемыми и не потеряют направление.
        • +1
          Потеряют, там проблема в том что направления регекспов навстречу друг другу, а у текста направление одно — слева направо.
        • +1
          Тогда они будут в обратном направлении относительно «матчимой» строки.
  • +3
    Лучше всего работает в ИЕ10… как ни странно.
    • 0
      Даже лучше, чем в Webkit? У меня, к сожалению, нет возможности самому это увидеть.
    • 0
      Лучше всего работает в ИЕ10… как ни странно.

      Это заговор!

  • +1
    Стоит счетчик времени на страницу добавить, от первой введенной буквы до последней правильной
    • 0
      ОК, добавил.
  • 0
    где-то минут за 40. Правда, под конец облажался в одном символе, и (.)(.)(.)(.) не сходилосб. пришлось подсмотреть его :(
  • 0
    Сначала хотел написать, что кроссворд не имеет решений, но потом понял, в чём проблема. При клике в клетку все тексты пишутся горизонтально, и для трёх граней порядок становится неправильным. Нужно тогда и само регулярное выражение разворачивать, что вроде не сильно сложно.
    • 0
      Порядок остаётся прежним. Подписи я кручу только для удобства чтения.
      А разворачивать регулярки как раз сложно (если не невозможно).
      • 0
        Надпись слева направо, а строка справа налево, следовательно, порядок неправильный.
        Что касается регулярок, то, может, и бывают такие, которые нельзя развернуть, но я сходу не смог таких придумать, а имеющиеся в кроссворде разворачиваются элементарно.
  • 0
    Спасибо за реализацию! Решить удалось. В хроме работает почти без проблем. Только в одной регулярке (где-то снизу справа) кажется лишний пробел видим.
    • 0
      Да, видел, и уже исправил.
  • 0
    стоит сделать систему пометок(в яейку вводить несколько символов, пока не знаешь, что именно там должно быть) как в судоку. хотя, это — дело вкуса.
  • +1
    Отлично! Решил за час и 48 минут. Многовато, но я отвлекался.
    Теперь знаю, какое задание на собеседованиях давать нужно =)
    • +2
      Если бы я увидел это задание на собеседовании, я бы встал и вышел.
      • 0
        Можно на дом давать, но так, чтобы простановка каждой буквы сразу отправлялась на сервер и записывалась с временем. Далее по логу легко понять, списывал претендент или нет. Даже если человек списывая сможет обмануть логирование то его за одно это взять можно будет =)
        • 0
          Вы не решили основную проблему: задача совершенно не подходит для собеседований. Ни на одну должность. Ни в одну компанию мира. Ни в прошлом, ни в настоящем, ни в будущем.
          • 0
            Почему же? Задача дает понять, что собеседуемый умеет работать с регулярками и в общем неплохо их понимает. Там ведь и группировка, и наборы, и повторение. Не все конечно но основы есть.
            • 0
              Вы не чувствуете разницы между пониманием регулярных выражений и умением решать составленные из них кроссворды? Не говоря уж о том, что выучить 90% синтаксиса регулярных выражений можно за несколько часов с нуля, поэтому подобная проверка знаний бессмысленна; да и что не существует профессий, в которых ощутимое время занимает анализ регулярных выражений.
              • 0
                Но существуют профессии в которых 90% времени занимает написание регулярных выражений. Сам знаком с парой подобных специалистов =)
                • +1
                  90%? И чем же они занимаются?.. о_О
                  • 0
                    Пишут скрипты для парсинга страниц
  • 0
    1:36:10. Это были увлекательнейшие полтора часа!
    Всегда было интересно, как люди придумывают такие прикольные задачи — всё же настолько надо подогнать друг к дружке, чтобы и регекспы были простые и красивые, и решение было единственно, и решать было непросто. Респект авторам таких задач!
  • 0
    Хотел решить, ещё когда увидел в виде картинки, но терпения не хватило вертеть головой или крутить куски изображения в редакторе.
    В таком виде отлично просто, спасибо!
    0:59:20.
  • 0
    Почему-то под маком не ставится точка нигде (Chrome 26, Firefox 20, Safari 6.0.3)
  • 0
    Решил вчера впервые, сейчас решил повторить, не отвлекаясь.
    00:38:29
  • 0
    Спасибо, удобно решать в таком формате.
    02:07:01, в (...?)\1* сбился при повторении букв и через некоторое время пришлось долго разматывать и вспоминать, какие кобминации не обоснованы :)
  • 0
    Жаль он не показывает, какую регулярку буква проваливает.
  • 0
    FF 24.5/Linux ячейки отрисовываются некорректно. При этом на сайте «честных полигонов» всё в порядке.
  • 0

    На планшете не отображает клавиатуру для ввода символов.

  • +1
    Хотелось бы видеть код на GitHub… Может быть выложите?

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.