England met the Springboks challenge head on at Kings Park and were level at 6-6 at half-time after Owen Farrell and Steyn traded penalties.
South Africa began to gain the upper hand after the break as Steyn and captain De Villiers broke through and the hosts held on despite two more Farrell penalties applying pressure.
Ben Foden claimed a late England consolation after the final hooter and head coach Stuart Lancaster will take some heart from the fighting display of his players.
Despite that, what was England’s eighth successive Test loss to the Springboks still leaves them facing an uphill fight to win their first three-match series in South Africa.
The scoreline might have been close but the normally reliable Steyn, who still scored 17 of his side’s points, did miss two conversions and a penalty.
Heavy rain eased before kick-off but the surface remained slick.
The Springboks imposed themselves early on with some powerful hits and the more expansive handling of the two sides, while England also went hard into their tackles, hoping to force their opponents back.
The South Africans matched this commitment, eventually pushing further ahead with Steyn’s late penalty. England visibly ran out of steam as Steyn popped up again to add another in the closing moments.
Scorers: South Africa: Tries: M Steyn, de Villiers. Pens: M Steyn 4. England: Try: Foden. Pens: Farrell 4.
South Africa: Kirchner, Pietersen, de Vi lliers (c), F Steyn, Habana, M Steyn, Hougaard, Spies, Alberts, Coetzee, Kruger, Etzebeth, J du Plessis, B du Plessis, Mtawarirae. Subs: Strauss, Oosthuizen, van der Merwe, Daniel, Pienaar, Lambie, Olivier.
England: Brown, Ashton, Tuilagi, Barritt, Foden, Farrell, Youngs, Morgan, Robshaw (c), Johnson, Parling, Botha, Cole, Hartley, Marler. Subs: Mears, Doran-Jones, Palmer, Dowson, Dickson, Flood, Joseph.
Referee: S Walsh (Aus). Attendance: 43,052.