main.scss 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. @import "helpers";
  2. @import "fonts/clear-sans.css";
  3. $field-width: 500px;
  4. $grid-spacing: 15px;
  5. $grid-row-cells: 4;
  6. $tile-size: ($field-width - $grid-spacing * ($grid-row-cells + 1)) / $grid-row-cells;
  7. $tile-border-radius: 3px;
  8. $mobile-threshold: $field-width + 20px;
  9. $text-color: #776E65;
  10. $bright-text-color: #f9f6f2;
  11. $tile-color: #eee4da;
  12. $tile-gold-color: #edc22e;
  13. $tile-gold-glow-color: lighten($tile-gold-color, 15%);
  14. $game-container-margin-top: 40px;
  15. $game-container-background: #bbada0;
  16. $transition-speed: 100ms;
  17. html, body {
  18. margin: 0;
  19. padding: 0;
  20. background: #faf8ef;
  21. color: $text-color;
  22. font-family: "Clear Sans", "Helvetica Neue", Arial, sans-serif;
  23. font-size: 18px;
  24. }
  25. body {
  26. margin: 80px 0;
  27. }
  28. .heading {
  29. @include clearfix;
  30. }
  31. h1.title {
  32. font-size: 80px;
  33. font-weight: bold;
  34. margin: 0;
  35. display: block;
  36. float: left;
  37. }
  38. @include keyframes(move-up) {
  39. 0% {
  40. top: 25px;
  41. opacity: 1;
  42. }
  43. 100% {
  44. top: -50px;
  45. opacity: 0;
  46. }
  47. }
  48. .scores-container {
  49. float: right;
  50. text-align: right;
  51. }
  52. .score-container, .best-container {
  53. $height: 25px;
  54. position: relative;
  55. display: inline-block;
  56. background: $game-container-background;
  57. padding: 15px 25px;
  58. font-size: $height;
  59. height: $height;
  60. line-height: $height + 22px;
  61. font-weight: bold;
  62. border-radius: 3px;
  63. color: white;
  64. margin-top: 8px;
  65. text-align: center;
  66. &:after {
  67. position: absolute;
  68. width: 100%;
  69. top: 10px;
  70. left: 0;
  71. text-transform: uppercase;
  72. font-size: 13px;
  73. line-height: 13px;
  74. text-align: center;
  75. color: $tile-color;
  76. }
  77. .score-addition {
  78. position: absolute;
  79. right: 30px;
  80. color: red;
  81. font-size: $height;
  82. line-height: $height;
  83. font-weight: bold;
  84. color: rgba($text-color, .9);
  85. z-index: 100;
  86. @include animation(move-up 600ms ease-in);
  87. @include animation-fill-mode(both);
  88. }
  89. }
  90. .score-container:after {
  91. content: "Score";
  92. }
  93. .best-container:after {
  94. content: "Best"
  95. }
  96. p {
  97. margin-top: 0;
  98. margin-bottom: 10px;
  99. line-height: 1.65;
  100. }
  101. a {
  102. color: $text-color;
  103. font-weight: bold;
  104. text-decoration: underline;
  105. cursor: pointer;
  106. }
  107. strong {
  108. &.important {
  109. text-transform: uppercase;
  110. }
  111. }
  112. hr {
  113. border: none;
  114. border-bottom: 1px solid lighten($text-color, 40%);
  115. margin-top: 20px;
  116. margin-bottom: 30px;
  117. }
  118. .container {
  119. width: $field-width;
  120. margin: 0 auto;
  121. }
  122. @include keyframes(fade-in) {
  123. 0% {
  124. opacity: 0;
  125. }
  126. 100% {
  127. opacity: 1;
  128. }
  129. }
  130. // Styles for buttons
  131. @mixin button {
  132. display: inline-block;
  133. background: darken($game-container-background, 20%);
  134. border-radius: 3px;
  135. padding: 0 20px;
  136. text-decoration: none;
  137. color: $bright-text-color;
  138. height: 40px;
  139. line-height: 42px;
  140. }
  141. // Game field mixin used to render CSS at different width
  142. @mixin game-field {
  143. .game-container {
  144. margin-top: $game-container-margin-top;
  145. position: relative;
  146. padding: $grid-spacing;
  147. cursor: default;
  148. -webkit-touch-callout: none;
  149. -ms-touch-callout: none;
  150. -webkit-user-select: none;
  151. -moz-user-select: none;
  152. -ms-user-select: none;
  153. -ms-touch-action: none;
  154. touch-action: none;
  155. background: $game-container-background;
  156. border-radius: $tile-border-radius * 2;
  157. width: $field-width;
  158. height: $field-width;
  159. -webkit-box-sizing: border-box;
  160. -moz-box-sizing: border-box;
  161. box-sizing: border-box;
  162. .game-message {
  163. display: none;
  164. position: absolute;
  165. top: 0;
  166. right: 0;
  167. bottom: 0;
  168. left: 0;
  169. background: rgba($tile-color, .5);
  170. z-index: 100;
  171. text-align: center;
  172. p {
  173. font-size: 60px;
  174. font-weight: bold;
  175. height: 60px;
  176. line-height: 60px;
  177. margin-top: 222px;
  178. // height: $field-width;
  179. // line-height: $field-width;
  180. }
  181. .lower {
  182. display: block;
  183. margin-top: 59px;
  184. }
  185. a {
  186. @include button;
  187. margin-left: 9px;
  188. // margin-top: 59px;
  189. &.keep-playing-button {
  190. display: none;
  191. }
  192. }
  193. @include animation(fade-in 800ms ease $transition-speed * 12);
  194. @include animation-fill-mode(both);
  195. &.game-won {
  196. background: rgba($tile-gold-color, .5);
  197. color: $bright-text-color;
  198. a.keep-playing-button {
  199. display: inline-block;
  200. }
  201. }
  202. &.game-won, &.game-over {
  203. display: block;
  204. }
  205. }
  206. }
  207. .grid-container {
  208. position: absolute;
  209. z-index: 1;
  210. }
  211. .grid-row {
  212. margin-bottom: $grid-spacing;
  213. &:last-child {
  214. margin-bottom: 0;
  215. }
  216. &:after {
  217. content: "";
  218. display: block;
  219. clear: both;
  220. }
  221. }
  222. .grid-cell {
  223. width: $tile-size;
  224. height: $tile-size;
  225. margin-right: $grid-spacing;
  226. float: left;
  227. border-radius: $tile-border-radius;
  228. background: rgba($tile-color, .35);
  229. &:last-child {
  230. margin-right: 0;
  231. }
  232. }
  233. .tile-container {
  234. position: absolute;
  235. z-index: 2;
  236. }
  237. .tile {
  238. &, .tile-inner {
  239. width: ceil($tile-size);
  240. height: ceil($tile-size);
  241. line-height: $tile-size + 10px;
  242. }
  243. // Build position classes
  244. @for $x from 1 through $grid-row-cells {
  245. @for $y from 1 through $grid-row-cells {
  246. &.tile-position-#{$x}-#{$y} {
  247. $xPos: floor(($tile-size + $grid-spacing) * ($x - 1));
  248. $yPos: floor(($tile-size + $grid-spacing) * ($y - 1));
  249. @include transform(translate($xPos, $yPos));
  250. }
  251. }
  252. }
  253. }
  254. }
  255. // End of game-field mixin
  256. @include game-field;
  257. .tile {
  258. position: absolute; // Makes transforms relative to the top-left corner
  259. .tile-inner {
  260. border-radius: $tile-border-radius;
  261. background: $tile-color;
  262. text-align: center;
  263. font-weight: bold;
  264. z-index: 10;
  265. font-size: 55px;
  266. }
  267. // Movement transition
  268. @include transition($transition-speed ease-in-out);
  269. -webkit-transition-property: -webkit-transform;
  270. -moz-transition-property: -moz-transform;
  271. transition-property: transform;
  272. $base: 2;
  273. $exponent: 1;
  274. $limit: 11;
  275. // Colors for all 11 states, false = no special color
  276. $special-colors: false false, // 2
  277. false false, // 4
  278. #f78e48 true, // 8
  279. #fc5e2e true, // 16
  280. #ff3333 true, // 32
  281. #ff0000 true, // 64
  282. false true, // 128
  283. false true, // 256
  284. false true, // 512
  285. false true, // 1024
  286. false true; // 2048
  287. // Build tile colors
  288. @while $exponent <= $limit {
  289. $power: pow($base, $exponent);
  290. &.tile-#{$power} .tile-inner {
  291. // Calculate base background color
  292. $gold-percent: ($exponent - 1) / ($limit - 1) * 100;
  293. $mixed-background: mix($tile-gold-color, $tile-color, $gold-percent);
  294. $nth-color: nth($special-colors, $exponent);
  295. $special-background: nth($nth-color, 1);
  296. $bright-color: nth($nth-color, 2);
  297. @if $special-background {
  298. $mixed-background: mix($special-background, $mixed-background, 55%);
  299. }
  300. @if $bright-color {
  301. color: $bright-text-color;
  302. }
  303. // Set background
  304. background: $mixed-background;
  305. // Add glow
  306. $glow-opacity: max($exponent - 4, 0) / ($limit - 4);
  307. @if not $special-background {
  308. box-shadow: 0 0 30px 10px rgba($tile-gold-glow-color, $glow-opacity / 1.8),
  309. inset 0 0 0 1px rgba(white, $glow-opacity / 3);
  310. }
  311. // Adjust font size for bigger numbers
  312. @if $power >= 100 and $power < 1000 {
  313. font-size: 45px;
  314. // Media queries placed here to avoid carrying over the rest of the logic
  315. @include smaller($mobile-threshold) {
  316. font-size: 25px;
  317. }
  318. } @else if $power >= 1000 {
  319. font-size: 35px;
  320. @include smaller($mobile-threshold) {
  321. font-size: 15px;
  322. }
  323. }
  324. }
  325. $exponent: $exponent + 1;
  326. }
  327. // Super tiles (above 2048)
  328. &.tile-super .tile-inner {
  329. color: $bright-text-color;
  330. background: mix(#333, $tile-gold-color, 95%);
  331. font-size: 30px;
  332. @include smaller($mobile-threshold) {
  333. font-size: 10px;
  334. }
  335. }
  336. }
  337. @include keyframes(appear) {
  338. 0% {
  339. opacity: 0;
  340. @include transform(scale(0));
  341. }
  342. 100% {
  343. opacity: 1;
  344. @include transform(scale(1));
  345. }
  346. }
  347. .tile-new .tile-inner {
  348. @include animation(appear 200ms ease $transition-speed);
  349. @include animation-fill-mode(backwards);
  350. }
  351. @include keyframes(pop) {
  352. 0% {
  353. @include transform(scale(0));
  354. }
  355. 50% {
  356. @include transform(scale(1.2));
  357. }
  358. 100% {
  359. @include transform(scale(1));
  360. }
  361. }
  362. .tile-merged .tile-inner {
  363. z-index: 20;
  364. @include animation(pop 200ms ease $transition-speed);
  365. @include animation-fill-mode(backwards);
  366. }
  367. .above-game {
  368. @include clearfix;
  369. }
  370. .game-intro {
  371. float: left;
  372. line-height: 42px;
  373. margin-bottom: 0;
  374. }
  375. .restart-button {
  376. @include button;
  377. display: block;
  378. text-align: center;
  379. float: right;
  380. }
  381. .game-explanation {
  382. margin-top: 50px;
  383. }
  384. @include smaller($mobile-threshold) {
  385. // Redefine variables for smaller screens
  386. $field-width: 280px;
  387. $grid-spacing: 10px;
  388. $grid-row-cells: 4;
  389. $tile-size: ($field-width - $grid-spacing * ($grid-row-cells + 1)) / $grid-row-cells;
  390. $tile-border-radius: 3px;
  391. $game-container-margin-top: 17px;
  392. html, body {
  393. font-size: 15px;
  394. }
  395. body {
  396. margin: 20px 0;
  397. padding: 0 20px;
  398. }
  399. h1.title {
  400. font-size: 27px;
  401. margin-top: 15px;
  402. }
  403. .container {
  404. width: $field-width;
  405. margin: 0 auto;
  406. }
  407. .score-container, .best-container {
  408. margin-top: 0;
  409. padding: 15px 10px;
  410. min-width: 40px;
  411. }
  412. .heading {
  413. margin-bottom: 10px;
  414. }
  415. // Show intro and restart button side by side
  416. .game-intro {
  417. width: 55%;
  418. display: block;
  419. box-sizing: border-box;
  420. line-height: 1.65;
  421. }
  422. .restart-button {
  423. width: 42%;
  424. padding: 0;
  425. display: block;
  426. box-sizing: border-box;
  427. margin-top: 2px;
  428. }
  429. // Render the game field at the right width
  430. @include game-field;
  431. // Rest of the font-size adjustments in the tile class
  432. .tile .tile-inner {
  433. font-size: 35px;
  434. }
  435. .game-message {
  436. p {
  437. font-size: 30px !important;
  438. height: 30px !important;
  439. line-height: 30px !important;
  440. margin-top: 90px !important;
  441. }
  442. .lower {
  443. margin-top: 30px !important;
  444. }
  445. }
  446. }