body.w-screen.h-screen.ctr
	.tabel.ctr
		.board
			span#col-0
			span#col-1
			span#col-2
			span#col-3
			span#col-4
			span#col-5
			span#col-6
			span#col-7
			span#col-8
		button#reset Reset
			
	//design on dribbble: https://dribbble.com/shots/6546099-Empty-Spaces-10
View Compiled
@import url('https://fonts.googleapis.com/css?family=Press+Start+2P&display=swap')
*
	font-family: 'Press Start 2P', cursive
	user-select: none
$size: 480px
.ctr
	display: flex
	justify-content: center
	align-items: center

body
	background: #285CA1

.tabel
	width: $size
	height: $size
	background: #76AFD6
	border-radius: 100%
	border: 1px solid #0D152B
	box-shadow: -2px 20px 0 -3px #4283C4, -20px 20px #0D152B
	flex-direction: column

.board
	width: $size / 1.3
	height: $size / 1.3
	background: #D3E2EA
	border-radius: 20px
	border: 1px solid #0D152B
	box-shadow: -10px 5px 0px -2px lighten(#0D152B, 10%)
	display: grid
	grid-template-rows: repeat(3, 1fr)
	grid-template-columns: repeat(3, 1fr)
	grid-gap: 8px
	padding: 12px
	

.board > span
	background: #76AFD6
	color: #fff
	font-size: 4em
	padding-left: 9px
	padding-top: 6px
	text-align: center
	border: 2px solid #0D152B
	border-radius: 5px
	cursor: pointer
	transition: all .2s ease
	box-shadow: -1.2px 2px 0px 0px #141D4C
	&:hover
		background: darken(#76AFD6, 3%)
	&:active
		box-shadow: -1.2px 7.4px 0px -2.5px #141D4C

#reset
	margin-top: 14px
	color: #fff
	

.win
	background: #55efc4 !important
View Compiled
'use strict'

const _ = document,
          cols = Array.from(_.querySelectorAll('.board > span')),
					reset = _.querySelector('#reset')
let cur = true
let arr = new Array(9).fill(null)
const wins = [
  [0, 1, 2],
  [3, 4, 5],
  [6, 7, 8],
  [0, 3, 6],
  [1, 4, 7],
  [2, 5, 8],
  [0, 4, 8],
  [2, 4, 6]
]
function event(can) {
	reset.addEventListener('click', fnreset)
  for(let col of cols)
    if(can)
      col.addEventListener('click', play)
    else
      col.removeEventListener('click', play)
}
event(true)
function play(e) {
  const __ = e.target
  if(!__.innerHTML){
    cur = !cur
    __.innerHTML = cur ? '<h1 name="O">O</h1>' :  '<h1 name="X">X</h1>'
    move(parseInt(__.id.split(/\D+/g)[1]), __.childNodes[0].getAttribute('name'))
  }
}

function move(ind, sign) {
  arr[ind] = sign
  console.log(arr)

  for (let i = 0; i < wins.length; i++) {
     let [a, b, c] = wins[i] 
      if(cmp(arr[a], arr[b], arr[c])){
        console.log(sign, ' wins')
        event(false)
        cols[a].classList.add('win')
        cols[b].classList.add('win')
        cols[c].classList.add('win')
      }
  }
}
function cmp(a, b, c) {
  if(a && b && c)
    return (a === b) && (a === c) && (b === c)
}

function fnreset() {
    for(let col of cols){
      col.classList.remove('win')
      col.innerHTML = ''
    }
    arr = new Array(9).fill(null)
    event(true)
}

External CSS

  1. https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/1.0.2/tailwind.min.css

External JavaScript

This Pen doesn't use any external JavaScript resources.