クリックした文字同士を入れ替えます。
JSはやたら長いですが単純にクラスを付け替えているだけで、後はCSSアニメーションに任せています。
謎のちらつきは謎のままです。FFだときれいに見えます。
See the Pen hello world. by kimmy (@kimmy) on CodePen.
HTML
<div class="trade"> <span class="txt t1">H</span> <span class="txt t2">E</span> <span class="txt t3">L</span> <span class="txt t4">L</span> <span class="txt t5">O</span> <span class="txt t6">W</span> <span class="txt t7">O</span> <span class="txt t8">R</span> <span class="txt t9">L</span> <span class="txt t10">D</span> </div>
CSS
body { padding: 40px; background: #000; } .trade { position: relative; } .trade .txt { position: absolute; width: 24px; color: #fff; font: 30px Copperplate, sans-serif; text-align: center; white-space: nowrap; cursor: pointer; -webkit-transition: -webkit-transform .2s ease, top .5s ease, left .5s ease; transition: transform .2s ease, top .5s ease, left .5s ease; } .trade .txt.t1 { left: 30px; } .trade .txt.t2 { left: 60px; } .trade .txt.t3 { left: 90px; } .trade .txt.t4 { left: 120px; } .trade .txt.t5 { left: 150px; } .trade .txt.t6 { left: 195px; } .trade .txt.t7 { left: 230px; } .trade .txt.t8 { left: 260px; } .trade .txt.t9 { left: 290px; } .trade .txt.t10 { left: 320px; } .trade .txt.t10:after { content: "."; } .trade .txt.on { z-index: -1; -webkit-transform: scale(0.9); -ms-transform: scale(0.9); transform: scale(0.9); -webkit-animation: shake .1s ease 0s infinite normal; animation: shake .1s ease 0s infinite normal; } @-webkit-keyframes shake { 0% { margin: -1px; } 25% { margin: 1px 0 0 -1px; } 50% { margin: -1px 0 0 1px; } 100% { margin: 1px; } } @keyframes shake { 0% { margin: -1px; } 25% { margin: 1px 0 0 -1px; } 50% { margin: -1px 0 0 1px; } 100% { margin: 1px; } }
JavaScript
(function (win, doc, $) { "use strict"; win.app = win.app || {}; })(this, document, $); (function (win, doc, $, ns) { "use stricr"; function EventDispatcher() { this._events = {}; } EventDispatcher.prototype.hasEventListener = function(eventName) { return !!this._events[eventName]; }; EventDispatcher.prototype.addEventListener = function(eventName, callback) { if (this.hasEventListener(eventName)) { var events = this._events[eventName]; for (var i in events) { if (events[i] === callback) { return; } } events.push(callback); } else { this._events[eventName] = [callback]; } }; EventDispatcher.prototype.removeEventListener = function(eventName, callback) { if (!this.hasEventListener(eventName)) { return; } else { var events = this._events[eventName], i = events.length, index; while (i--) { if (events[i] === callback) { index = i; } } events.splice(index, 1); } }; EventDispatcher.prototype.fireEvent = function(eventName, opt_this) { if (!this.hasEventListener(eventName)) { return; } else { var events = this._events[eventName], copyEvents = $.merge([], events), arg = $.merge([], arguments); arg.splice(0, 2); for (var i in copyEvents) { copyEvents[i].apply(opt_this || this, arg); } } }; ns.EventDispatcher = EventDispatcher; })(this, document, $, app); (function (win, doc, $, ns) { "use strict"; var EventDispatcher = ns.EventDispatcher, originalConstructor, instance; function CellManager() { var _cells = [], _queue = [], _count = 0; EventDispatcher.call(this); function _trade(cell1, cell2) { var className = cell1.getClass(); cell1.setClass(cell2.getClass()); cell2.setClass(className); setTimeout(function() { cell1.off(); cell2.off(); }, 500); } function push(cell) { _cells.push(cell); } function on(cell) { ++_count; _queue[1] = _queue[0]; _queue[0] = cell; if (_count > 1) { _trade(_queue[0], _queue[1]); } } function off(cell) { if (_count) { --_count; } } function shuffle() { var length = _cells.length, queue = [], i = 0, j = 0; for (; i < length; i++) { queue.push(i); } for (; j < length; j++) { _cells[queue.splice(Math.random() * queue.length | 0, 1)].on(); } } this.push = push; this.on = on; this.off = off; this.shuffle = shuffle; } originalConstructor = CellManager.prototype.constructor; CellManager.prototype = new EventDispatcher(); CellManager.prototype.constructor = originalConstructor; CellManager.getInstance = function() { if (!instance) { instance = new CellManager(); } return instance; }; ns.CellManager = CellManager; })(this, document, $, app); (function (win, doc, $, ns) { "use strict"; var EventDispatcher = ns.EventDispatcher, originalConstructor; function CellController ($elm) { var that = this; EventDispatcher.call(this); this._$elm = $elm; _init(); function _init() { $elm.on("click", _handleClick); } function _handleClick() { that.toggle(); } } originalConstructor = CellController.prototype.constructor; CellController.prototype = new EventDispatcher(); CellController.prototype.constructor = originalConstructor; CellController.prototype.toggle = function () { if (this._$elm.hasClass("on")) { this.off(); } else { this.on(); } }; CellController.prototype.on = function () { this._$elm.addClass("on"); this.fireEvent("ON"); }; CellController.prototype.off = function () { this._$elm.removeClass("on"); this.fireEvent("OFF"); }; CellController.prototype.getClass = function () { return this._$elm[0].className; }; CellController.prototype.setClass = function (className) { this._$elm[0].className = className; return this; }; ns.CellController = CellController; })(this, document, $, app); (function(win, doc, $, ns) { "use strict"; var CellManager = ns.CellManager, CellController = ns.CellController; var cellManager = CellManager.getInstance(), $cells = $(".txt"), length = $cells.length, i = 0, cellController; for (; i < length; i++) { cellController = new CellController($cells.eq(i)); cellController.addEventListener("ON", _handleOnCell); cellController.addEventListener("OFF", _handleOffCell); cellManager.push(cellController); } function _handleOnCell() { cellManager.on(this, this); } function _handleOffCell() { cellManager.off(); } })(this, document, $, app);