Substitute Alvaro Morata got the winner in the 83rd minute to cap a 19-minute turnaround that keeps Real on course for their first La Liga triumph since 2012 after Barcelona's talisman Lionel Messi had briefly sent his side top with a late strike in the 2-1 victory at Atletico Madrid.
Real lead on 55 points, one ahead of Barcelona and three clear of Sevilla. Real also have a game in hand on both of their title rivals.
The first half was a lively affair which saw plenty of chances for both sides but all the goals came after the break.
Villarreal's Manu Trigueros lashed home from inside the area to put the hosts ahead on 50 minutes and Cedric Bakambu doubled the lead in the 57th with a fine finish past Keylor Navas, though he was fortunate not to be ruled offside.
Real looked destined for a second loss in a week on the east coast after Wednesday's 2-1 reverse at Valencia but Bale, making his first start since November, headed a goal back in the 64th before Ronaldo levelled with a controversial penalty 10 minutes later after Villarreal captain Bruno Soriano handled following a ricochet in the area.
[caption id="attachment_49259" align="aligncenter" width="768"]
Real Madrid's Cristiano Ronaldo heads the ball against Villarreal at El Madrigal AFP
Villarreal coach Fran Escriba and substitute Roberto Soldado were both sent off from the dugout for protesting the decision.
Morata then headed Marcelo's cross under Villarreal's substitute goalkeeper Andres Fernandez, who had replaced Sergio Asenjo after the first-choice stopper sustained a knee injury saving from Karim Benzema.
In Madrid, Messi came to Barcelona's rescue for the second time in a week by snatching a winner in the 86th minute to give his side a barely deserved win at Atletico.
Rafinha had put Luis Enrique's side ahead against the run of play with a scrappy finish in the 63rd minute but Godin nodded in Koke's free kick to level in the 70th.
For much of the game, Barca looked to be suffering a lack of confidence from their 4-0 thrashing at Paris St Germain in the Champions League. They made a timid start and had goalkeeper Marc-Andre ter Stegen to thank for impressive saves in either half.
It took a scrappy strike from Rafinha Alcantara to break the deadlock, the Brazilian firing into the far corner when the ball bounced fortuitously towards him, while Messi also benefited from a lucky ricochet to settle the game, adding to the late winner he had scored against Leganes the week before.
(Caicedo 17, Jurado 46, Moreno 90+1) Osasuna 0
(Godin 70) Barcelona 2
(Rafinha 63, Messi 86)
(Susaeta 11, Lekue 33, San Jose 69) Granada 1
(Gomez 49-P) Celta 1
(Trigueros 50, Bakambu 56) Real Madrid 3
(Bale 64, Ronaldo 74-P, Morata 83)
P W D L GD Pts
23 17 4 2 38 55
24 16 6 2 45 54
24 16 4 4 19 52
24 13 6 5 23 45
24 14 2 8 5 44
24 11 9 4 14 39