Spain's Alvaro Morata and Mikel Oyarzabal scored to finally settle an eventful contest in Copenhagen that ended 3-3 after 90 minutes.
Croatia had taken an unexpected early lead when Spain goalkeeper Unai Simon allowed a back-pass from Pedri to squirm into the net.
Spain responded superbly through Pablo Sarabia, Cesar Azpilicueta and Ferran Torres but Croatia hit back with two goals in the last five minutes of normal time from substitutes Mislav Orsic and Mario Pasalic.
Kylian Mbappe saw his penalty saved in the shoot-out as Euro 2020 favourites France crashed out.
There had been nine successful kicks in the shoot-out before Yann Sommer saved Mbappe's effort, following an entertaining 3-3 draw in Bucharest.
Switzerland had fought back from 3-1 down to force extra time with two goals in the final 10 minutes through Haris Seferovic and Mario Gavranovic, after two quickfire goals from Karim Benzema and a superb strike from Paul Pogba had overturned the early lead given to the Swiss by Seferovic.
The first penalties of the tournament
World champions France fell at the first knockout stage in the first penalty shoot-out of the tournament, with Mbappe missing the decisive spot-kick.
Switzerland goalkeeper Sommer dived to his right to keep the penalty out, with the Swiss going through having been 3-1 down with nine minutes of normal time remaining.
Spain survive Croatia test
Croatia carried their momentum into extra time but Simon made a fine save and Spain ultimately went on to secure a place in the last eight. Spain remarkably found themselves behind after 20 minutes when Simon switched off, with normal time finishing 3-3 after two goals from Croatia in the final 10 minutes of normal time.
Morata then delivered a strong riposte to his critics by firing Spain into a 4-3 lead with a ferocious strike into the roof of the net in the 100th minute.
Moments later, Spain had a two-goal lead again as substitute Oyarzabal raced into the box to meet a fine ball from Dani Olmo and tuck home.
Stat of the day
Quote of the day
Post of the day
Up next
England v Germany (Round of 16, June 29, London, 1700 BST)
Sweden v Ukraine (Round of 16, June 29, Glasgow, 2000 BST)